Select 分组依据中的非聚合列,基于相关聚合列

Select non-aggregate column in a group by, based on a related aggregate column

我正在尝试从数据库中获取对话列表,并且我希望与它们一起显示最新消息。我无法找到允许我执行此操作的查询(而且不是 N+1)。

我有这些表:

chats(id, user_id, post_id, created_at)
messages(id, user_id, chat_id, body, created_at)

我有这样一个疑问:

select chats.id, chats.user_id, m.latest from chats
inner join (
    select chat_id, max(created_at) as latest from messages
    group by chat_id
) as m on m.chat_id = chats.id; 

但我想从 max(created_at) 结果对应的行中添加消息正文。有没有可能得到这样的相关专栏?

尝试使用 ROW_NUMBER() :

select chats.id, chats.user_id, m.body from chats
inner join (
    select chat_id,body ,
           row_number() OVER(PARTITION BY chat_id ORDER BY created_at DESC) as rnk
    from messages
) m on m.chat_id = chats.id and m.rnk = 1;

使用标准 SQL 这可以使用 window 函数来完成(参见 sagi 的回答)。

对于 Postgres,专有的 distinct on() 通常比使用 window 函数的等效解决方案更快:

select chats.id, chats.user_id, m.body, m.latest 
from chats
  join (
    select distinct on (chat_id) chat_id, body, created_at as latest 
    from messages
    order by chat_id, created_at desc;
  ) as m on m.chat_id = chats.id; 

不过,使用 window 函数的解决方案更加灵活。您还可以获得最新的两条(或三条或...)消息,而 distinct on() 只会让您收到一条消息。