Нужна помощь с запросом

BRat

o_0
Нужна помощь с запросом

PHP:
SELECT *, msg.date as msg_date FROM #__msgs AS msg
                LEFT JOIN #__senders AS sender
                ON msg.id=sender.msg_id
                LEFT JOIN #__users AS user
                ON sender.user_id = user.id
                WHERE msg.is_private=0 OR (msg.is_private=1 AND sender.user_id={$this->id})
                ORDER BY msg.id DESC
                LIMIT 50
Есть такой запрос - он должен извлекать из таблицы msg все общие сообщения, и приватные сообщения для|от конретного пользователя. в таблице msg хранится информация о сообщении, в senders - кто отправил, кому отправлено, а в users - инфа о юзере.
senders:
PHP:
Field      Type                   Null    Key     Default  Extra           Privileges                     
---------  ---------------------  ------  ------  -------  --------------  -------------------------------
id         mediumint(8) unsigned          PRI     (NULL)   auto_increment  select,insert,update,references
msg_id     mediumint(8) unsigned          MUL     0                        select,insert,update,references
user_id    smallint(5) unsigned           MUL     0                        select,insert,update,references
user_role  enum('from','to')      YES             (NULL)                   select,insert,update,references
Соотвественно проблема запроса в том, что приватные сообщения извлекаются некорректно, а именно - из таблицы senders извлекается только одна запись - с sender.user_id={$this->id}. Можно ли каким-нибудь образом перестроить запрос так, чтобы извлекались все записи?

PS. Хм, нашел еще один недочет в запросе - LIMIT 50 выберет не 50 сообщений, а 50 юзеров, т.е. видимо спасет меня только разбиение запроса на два
 

BRat

o_0
PHP:
msgs:

Field       Type                   Null    Key     Default  Extra           Privileges                     
----------  ---------------------  ------  ------  -------  --------------  -------------------------------
id          mediumint(8) unsigned          PRI     (NULL)   auto_increment  select,insert,update,references
msg         text                                                            select,insert,update,references
color       varchar(7)                             #000000                  select,insert,update,references
is_private  tinyint(1)                     MUL     0                        select,insert,update,references
date        timestamp(14)          YES             (NULL)                   select,insert,update,references
users - интереса не представляет, там стандартная таблица с профилями юзеров
 

Krishna

Продался Java
BRat
Какая-то удивительная схема бд.

Как определяется автор и адресат сообщения, если в senders можно задать только 1 user_id? Или-или? Либо знаем кто, либо куда? Или одному сообщению должно соответствовать 2 записи в sender?
 

BRat

o_0
Krishna
и 2, и 3, и 103 ) в senders также задается user_role - 'from' или 'to' ..соответсвенно если отправлено 10 пользователям - будет 11 записей в senders, 1 - с from и 10 - с to
 

alpine

Новичок
BRat
Попробуй так:
[sql]
SELECT * FROM users as u
LEFT JOIN senders as s ON ( u.id=s.user_id )
LEFT JOIN messages as m ON ( m.id=s.msg_id )
WHERE m.is_private=0 OR ( m.is_private=1 AND u.id='some_id' )
ORDER BY m.id DESC
LIMIT 50
[/sql]
 

Krishna

Продался Java
BRat
Ок, даже если нужно уметь рассылать одно сообщение массово - ИМХО проще и логичнее сделать отдельные поля author_id (автор) и receiver_id (получатель). И запросы писать сразу станет легче :)
 

BRat

o_0
Krishna
так receiver_id может быть много, предлагаешь в это поле писать id'ы получателей через запятую? тогда вообще придется LIKE по полю receiver_id делать.. по моему у меня попроще всё-таки
alpine
а всё равно не 50 сообщений выдастся ) будут повторения из-за того что в таблице senders несколько записей соответсвует одному сообшению
+ забыл написать - не у всех сообщений есть автор, и есть получатель, есть сообщения информационные, типа Пользователь вошел в чат, пользователь вышел из чата.
 

alpine

Новичок
BRat
Ты типа задачу усложняешь? :)

-~{}~ 13.12.06 22:13:

Слушай давай ты напишешь каких конкретно 50 сообщений ты собираешься выбрать, какие виды сообщений могут быть и по каким параметрам этот вид определяется. Только пожалуйста внятно.
 

BRat

o_0
alpine
не, просто забыл..задача такая и была )

Структуру таблиц я описал выше, в таблице msgs хранятся сообщения, по одной записи на сообщение, из полей для нас имеют значения только id и is_private, показывающее является ли сообщение приватным или общим. Таблица senders связана с таблицей msgs по полю msg_id, в ней хранятся отправитель и получатели сообщения, по одной записи на человека, в msg_id - id сообщения, в user_id - id юзера, а в user_role - его роль (from - от, to - кому).
У сообщений может быть отправитель, могут быть получатели. может быть и то и то, может не быть ни того ни сего ) Т.е. кол-во записей в senders, связанных c msgs может варьироваться от 0 до ...
Таблица users - для упрощения можно ее откинуть

Мне нужно извлечь 50 сообщений из msgs, у которых либо флаг is_private=0 либо is_private=1 и текущий юзер принимает в приеме или отправке сообщения какое-то участие ) Это наверно видно из первого запроса

Собственно я уже сделал в два запроса - одним получаю 50 сообщений из msgs с требуемыми параметрами, а вторым - уже инфу об участвующих юзерах, и зря наверно вас напрягаю :)

PS хотя можно еще поговорить о неудачности данной структуры )
 

alpine

Новичок
BRat
хотя можно еще поговорить о неудачности данной структуры
Объедини две таблицы в одну, само же напрашивается.

-~{}~ 14.12.06 00:44:

так receiver_id может быть много, предлагаешь в это поле писать id'ы получателей через запятую? тогда вообще придется LIKE по полю receiver_id делать.. по моему у меня попроще всё-таки
Продублируй это сообщение столько раз сколько receiver_id. Для бродкаст сообщений ставь к примеру receiver_id=0.
 

Krishna

Продался Java
Krishna
так receiver_id может быть много, предлагаешь в это поле писать id'ы получателей через запятую? тогда вообще придется LIKE по полю receiver_id делать.. по моему у меня попроще всё-таки
Нет, я предлагаю делать несколько записей в таблице senders. Собственно как и сейчас, только вместо статусного столбца "from" и "to" + id будут два столбца с id
Условия писать будет проще.
 

BRat

o_0
alpine, Krishna
так, не успеваю за ходом мысли ) вынес всё в одну таблицу, завел в ней два поля author_id и receiver_id, и третье - msg_id, и злосно дублирую все сообщения. Вопрос - а как мне это поможет выбрать 50 сообщений из этой таблицы (без дублирования :) ), и как мне это поможет выбрать приватные сообщения для/от определенного юзера (со всеми получателями разумеется)
 

Krishna

Продался Java
BRat
Я в одну таблицу ничего выносить не предлагал.
Я лишь предложил сменить 2 столбца. Выгода - проще писать запросы + для одного сообщения будет одна, а не две строки в senders.
 

BRat

o_0
Krishna
мне с одним столбцом попроще - я по нему с таблицей users обьединяю, а по двум обьединять будет сложнее
+ придется проверять оба столбца на наличии нужного user_id (для вычисления приватов)
+ запросов использующих столбец 'from', 'to' вообще не предполагается (обычный чат)..и в том формате что есть сейчас в php достаточно элегантно всё это обрабатывается
 

alpine

Новичок
BRat
а как мне это поможет выбрать 50 сообщений из этой таблицы (без дублирования )
GROUP_CONCAT(receiver_id) или GROUP_CONCAT(users.user_name) + GROUP BY author_id + WHERE author_id = "some_id" OR receiver_id = "some_id" OR receiver_id=0(бродкаст и служебные сообщения)
 

BRat

o_0
alpine
ех..не посчитай за издевательство - у меня MySQL 4.0.x ))) GROUP_CONCAT нет

пока оставлю как есть тогда..у меня запросы попроще несколько, но советы ваши запомню, пригодятся
 

alpine

Новичок
BRat
На 4.0.х можно довыбрать непопавшие в первую выборку записи вторым запросом без использования GROUP_CONCAT, в итоге два простых запроса и логика GROUP_CONCAT в коде, время выполнения должно быть приемлимым.
 

BRat

o_0
alpine
не. я просто пока не вижу преимуществ по сравнению с исходной структурой - там два простых запроса, тут два простых запроса. Но там без дублирования
 
Сверху