在MySQL中的JOIN中进行排序 - 每个用户的最新消息

时间:2012-01-25 12:24:49

标签: mysql join

获得了两个版本的查询。也不是我需要的......

尝试返回所有用户,以及 向该用户发送<或> 的最新消息的时间。另一个标记显示最后一条消息是来自当前行中的用户(因此他们是否'等待响应')。

最后,需要订购整个结果集,让这些用户先“等待响应”,然后按最新消息的时间进行排序。

版本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 个答案:

答案 0 :(得分:2)

最简单的方法应该是:

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