【问题标题】:How to get latest messages for each user in mysql? [duplicate]如何获取mysql中每个用户的最新消息? [复制]
【发布时间】:2020-12-25 21:51:56
【问题描述】:

我有数据库来存储客户和消息

我正在尝试获取所有客户的列表及其最新消息,例如 Messenger 中的第一个屏幕。

SELECT *
FROM message AS m
LEFT JOIN customer AS c ON c.id=m.sender_id
ORDER BY m.sent_at DESC

但这会返回所有用户的所有消息。我也试过这样做

SELECT * 
FROM message AS m
LEFT JOIN customer AS c ON c.id=m.sender_id
GROUP BY c.id

但这并不能在所有数据库上运行,并且不能对结果集进行排序以仅获取最新消息。

【问题讨论】:

  • 以表格格式提供样本数据和您想要的输出
  • 如果某些用户没有消息怎么办?这个用户必须返回 NULL 还是根本不能返回?您使用 LEFT 加入 - 您是否有属于不存在用户的消息?
  • 如果用户没有消息不应该返回。我应该使用 Inner Join,这是错误的问题。

标签: mysql sql datetime greatest-n-per-group window-functions


【解决方案1】:

一个选项使用row_number(),在 MySQL 8.0 中可用:

select *    -- better enumerate the columns you want here
from customer as c
left join (
    select m.*, row_number() over(partition by m.sender_id order by sent_at desc) rn
    from messages m
) m on on c.id = m.sender_id and m.rn = 1
order by m.sent_at desc

这将为您提供每位客户的最后一条消息。如果您想要更多消息,您可以更改rn 的条件(rn <= 3 会给您每个客户三个消息)。

请注意,我更改了left join 中表格的顺序,因此它允许没有消息的客户(而不是没有客户的消息,这可能没有意义)。

如果您运行的是早期版本,则替代方法是使用子查询进行过滤:

select *    -- better enumerate the columns you want here
from customer as c
left join messages m 
    on  m.sender_id = c.id
    and sent_at = (select min(m1.sent_at) from messages m1 where m1.sender_id = m.sender_id)

对于相关子查询的性能,考虑(sender_id, sent_at) 上的索引(理想情况下,这些列中不应有重复项)。

【讨论】:

  • 有趣的答案!你能解释这里发生了什么over(partition...?我从来没有见过这个。
  • @LV98:row_number()是一个窗口函数;它按发送时间降序排列具有相同发件人的记录。你可以阅读更多关于窗口函数in the documentation.
  • @GMB 它给出了类似#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(partition by m.sender_account_id order by m.sent_at desc ) rn from rtc_messa' at line 7. mysql version = 5.7.31-0ubuntu0.18.04.1的错误
  • @KshitijDhakal:我用早期版本的解决方案更新了我的答案。
猜你喜欢
  • 2019-04-13
  • 2016-11-02
  • 2015-05-12
  • 1970-01-01
  • 2014-11-04
  • 1970-01-01
  • 2014-01-18
  • 1970-01-01
  • 2012-08-08
相关资源
最近更新 更多