сложный SQL запрос с IF-ами

Есть таблица, хранящая переписку двух групп людей: пользователей и админов.

Пользователи и админы лежат в разных таблицах.

Таблица сообщений общая:

от_кого - ID (пользователя или админа)

кому - ID (пользователя или админа)

правило - "кто-кому" (пользователь-пользователю или админ пользователю и т.п.)

Как сформировать список сообщений, с именами кто кому писал ?

можно использовать IF и вложенные запросы:




SELECT IF(messages.rule=0, <------------------------------ админ, иначе юзер     

     (SELECT login FROM admins WHERE admins.id = messages.from),   <----- вложенный запрос имени админа

     (SELECT login FROM users WHERE users.id = messages.from) <----- иначе вложенный запрос имени юзера

) as name_from



Как это сделать? Или есть другое решение на AR ?

А можно грамотно спроектировать базу данных и потом не мучиться.

С такой схемой БД есть только одно решение - писать запросы на "чистом" SQL.

А в два запроса нельзя?

Можно, но что делать, если потребуется упорядочить результаты, скажем, по дате?

А можно пример? Юзеры и админы должны быть в разных таблицах.

Здесь правило простое: не нужно делать поле таблицы, которое может ссылаться либо на одну таблицу, либо на другую (внешним ключом такое поле уже не назовешь) в зависимости от какого-то условия.

Не очень понятно, почему юзеры и админы не могут лежать в одной таблице. Таблица сообщений приняла бы простой естественный вид: (sender_id, reciever_id, …).

Можно посмотреть в сторону БД представлений (CREATE VIEW для MySQL), чтобы обращаться к результату сложного запроса, как к таблице. Вот только не знаю, насколько это понравится ActiveRecord’у.

Например, если разрабатываемое приложение является модулем для другого. Там свою юзера, со своей струтурой таблиц и т.п. А тут - админы, тоже сами по себе.

Таблицу сообщений можно и переделать, вот только других вариантов я не вижу. Может есть идеи, чтобы простыми джоинами обойтись… ?

Ну если два запроса не подходят, хотя это явно не видно по запросу, то например так


SELECT u.login AS users_login, a.login AS admin_login, rule FROM messages m

LEFT JOIN users u ON m.from = u.id

LEFT JOIN admins a ON m.from = a.id

а дальше в пхп разбирать




if ( $row['rule'] == 0 ) {

$login = $row['admin_login'];

}

else {

$login = $row['users_login'];

}



более вариантов я не вижу.

А если админ-админу пишет, или юзер-юзеру ? Получается что нужно делать по 2 джоина для каждого поля, итого 4 - как мне кажется, уже несколько многовато :)

Совсем не факт, что IF будет работать быстрее, а меньшего числа джоинов в данном случае и не ищите, т.к. правил комбинаторики еще никто не отменял :)

С другой стороны, раз уж тут никакой речи не идет о поддержке целостности данных, то имена отправителя и получателя можно продублировать в таблице сообщений. Да, места для хранения данных потребуется больше, но скорость выборки будет максимальной. Однако если скорость никого особо не волнует и записей в таблицах не миллионы, то четыре джоина погоды не сделают. В общем, всё зависит от условий задачи.

Чем не вариант записывать админов и юзеров в 1 таблицу, и в этой таблице указывать админ или нет? Или же создать вторую таблицу, в которой будет содержатся ссылка на пользователя, что будет означать что он админ?

Вам не кажется что хранить роль в messages это бред? А если админ перестал быть админом, а стал пользователем?

Ваше предложение (записывать админов и юзеров в 1 таблицу и в этой таблице указывать админ или нет) - это по сути то же самое :)

>А если админ перестал быть админом, и стал пользователем?

А если автомобиль перестал быть автомобилем и стал велосипедом, сохранять госномер и техпаспорт? :)

[size="3"]Какие еще есть варианты решения такой задачи?[/size]

Пример конечно… Вы понимаете к чему я вёл? Был админ, стал юзером - прочитать переписку уже не сможем


Какие еще есть варианты решения такой задачи? 

Никаких. Ваша логика никому не ясна.


Например, если разрабатываемое приложение является модулем для другого. Там свою юзера, со своей струтурой таблиц и т.п. А тут - админы, тоже сами по себе.

Ну раз сами по себе, то нет смысла делать переписку.

Lion__, вы немного не поняли сути задачи. Обьясню на пальцах: есть некий сайт, со своими юзерами и со своим фнукционалом. К этому сайту мы “подключаем” отдельную систему, назовём её “поддержкой”. Поддержка должна общаться с пользователями и наоборот, так же пользователи могут общаться дург с другом внутри этой системы. Но админы из техподдержки не будут переходить в пользователи сайта, как и наоборот. Зачем придумывать проблемы там, где их нет? :)

А вот как грамотно организовать подобное общение - вполне конкретная и (надеюсь) понятная задача.

Возможно я не вижу более простых вариантов решения, по этому и советуюсь :)

Yuri!

Я делал уже систему тикетов. Все юзера, саппорты в одну таблицу, было поле group, в котором и указывалась группа. В чём проблема сделать так же?

Раз юзеры и админы не имеют ничего общего, то почему таблица сообщений должна быть общей? Делайте три таблицы: UserUserMessage, AdminAdminMessage, UserAdminMessage (в этой таблице нужно будет создать поле, указывающее, кто кому послал сообщение). При такой структуре можно легко сделать CONSTRAINT’ы и поддерживать тем самым целостность данных. Если вам потребуется таблица, где будут все сообщения вместе, то создавайте VIEW.

Или, как я написал в предыдущем сообщении, делайте одну таблицу-"свалку", где будут id получателя/отправителя, "правило", а заодно и вся необходимая информация об обоих (логин, имя…). Дешево и сердито.

А ещщёё… можно сделать что-то вроде

id_from, role_from, id_to, role_to, message

  • VIEW-шка для пользователей и админов:

id, role (admin=1, user=0), login итд…

(select id, 1,login … from admins)

union

(select id,0,login … from users)

Насчет быстродействия варианта не скажу ничего : ) <-- смайлик вырезан

Ещё для размышлений: не исключено, что эффективнее (быстрее, менее замороченно) выбрать всех (/нужных) пользователей и админов простым SELECT … where id in (). Итого 2 простых запроса по PK

А в PHP, после выполнения ещё одного запроса (нужный период, видимо - тоже ключиком будет?..) подставлять найденные в предыдущих значения.

В общем, методом тыка предлагаю замерять скорость на действующих таблицах (раз этак тыщщу, например) и поведать о результатах общественности ) А то развели демагогию…