Заказ в JOIN в MySQL - последнее сообщение на пользователя - PullRequest
2 голосов
/ 25 января 2012

Получил две версии запроса. И не совсем то, что мне нужно ..

Попытка вернуть всех пользователей вместе со временем последнего сообщения, отправленного либо ИЛИ от этого пользователя. Дополнительный флаг показывает, было ли это последнее сообщение от пользователя в текущей строке (следовательно, они «ожидают ответа»).

Наконец, весь набор результатов должен быть упорядочен таким образом, чтобы эти пользователи сначала ожидали ответа, а затем - во время последнего сообщения.

Версия 1:

SELECT `users`.*,
MAX(`messages`.`time_sent`) AS `_message_time_sent`,
(`messages`.`user_id` = `users`.`id`) AS `_message_awaiting_response` 
FROM `users` LEFT JOIN `messages` 
ON (`messages`.`user_id` = `users`.`id` OR `messages`.`to_user_id` = `users`.`id`) 
GROUP BY `users`.`id` 
ORDER BY `_message_awaiting_response` DESC, `messages`.`time_sent` DESC

Проблема с версией 1: «_message_sent_time» является правильным (через MAX), но флаг «_message_awaiting_response» всегда выводится из сообщения, которое появилось первым в соединении до того, как произошло MAX (), что может быть не недавнее сообщение.

Версия 2:

SELECT DISTINCT `users`.*,
`messages`.`time_sent` AS `_message_time_sent`,
(`messages`.`user_id` = `users`.`id`) AS `_message_awaiting_response`
FROM `users` LEFT JOIN `messages`
ON (`messages`.`user_id` = `users`.`id` OR `messages`.`to_user_id` = `users`.`id`) 
GROUP BY `users`.`id` 
ORDER BY `_message_awaiting_response` DESC, `messages`.`time_sent` DESC

В версии 2 проблема в основном та же - из-за отсутствия агрегатной функции MAX () первое сообщение, найденное в объединении (не самое последнее), выделяется DISTINCT.

Есть ли простой способ убедиться, что последнее сообщение направлено сюда?

P.S. Это должно работать в MySQL 4;)

1 Ответ

2 голосов
/ 25 января 2012

Самый простой способ сделать это должен быть:

SELECT * FROM
(SELECT `users`.*,
        `messages`.`time_sent` AS `_message_time_sent`,
        (`messages`.`user_id` = `users`.`id`) AS `_message_awaiting_response` 
 FROM `users` 
 LEFT JOIN `messages` 
        ON `messages`.`user_id` = `users`.`id` OR 
           `messages`.`to_user_id` = `users`.`id`
 ORDER BY `users`.`id`, `messages`.`time_sent` DESC
) V
GROUP BY V.`id` 
ORDER BY `_message_awaiting_response` DESC, `_message_time_sent` DESC

Однако следует подчеркнуть, что, хотя это, вероятно, будет работать , оно не может быть гарантированным для работы - неагрегированные, разгруппированные значения, включенные в сгруппированный оператор выбора, обычно являются первыми в порядок, но документация MySQL не описывает это поведение как надежное.

Альтернатива, которая всегда должна работать (при условии, что у данного пользователя нет нескольких сообщений с одной и той же отметкой времени):

select u.*,
       m.`time_sent` AS `_message_time_sent`,
       (m.`user_id` = u.`id`) AS `_message_awaiting_response` 
from `users` u
left join (select `user_id`, max(`time_sent`) AS `last_sent`
           from (select `time_sent`, `user_id` from `messages` union all
                 select `time_sent`, `to_user_id` `user_id` from `messages`) v
           group by `user_id`) lm
       on u.`user_id` = lm.`user_id`
left join `messages` m
       ON m.`time_sent` = lm.`last_sent` and 
          lm.`user_id` in (m.`user_id`, m.`to_user_id`)
ORDER BY `_message_awaiting_response` DESC, `_message_time_sent` DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...