【问题标题】:Sql query distinct + other columnsSql 查询 distinct + 其他列
【发布时间】:2015-07-21 16:12:15
【问题描述】:

例如,我有这样的 sql 消息表:

id from_user_id to_user_id 消息 1 1 2 你好 2 1 2 你好吗? 3 1 3 你在哪里?

并查询 SELECT DISTINCT to_user_id FROM 消息;它返回

to_user_id 2 3

但是,这还不够。我需要向其他用户显示 from_user_id(id=1) 的所有最后消息,并避免 N+1 查询问题。结果一定是这样的

id from_user_id to_user_id 消息 2 1 2 你好吗? 3 1 3 你在哪里?

【问题讨论】:

  • 最后一条消息的timestamp 有列吗?
  • 是的,是的,但这并不重要,我可以按 id 或其他列排序。更重要的是每个用户一次查询只能获得一行,顺序并不重要。

标签: sql postgresql distinct


【解决方案1】:

您将要进行自我加入:

SELECT    m.*
FROM      messages m
LEFT JOIN messages _m ON m.to_user_id = _m.to_user_id
AND       _m.id > m.id
WHERE     _m.id IS NULL

【讨论】:

  • 酷,你能说,我怎么能在 ActiveRecord 中做到这一点?我正在使用 Ruby on Rails
  • 很遗憾我对 Ruby on Rails 不熟悉
  • 如果有人对 ruby​​ on rails 感兴趣,类似:@messages = Message.joins('LEFT JOIN messages _m ON messages.to_user_id = _m.to_user_id AND _m.id > messages.id') .where("_m.id IS NULL")
【解决方案2】:

您可以使用分析函数 rank,并在一个组中对其进行排序...

select * from (
select id,
       from_user_id,
       to_user_id,
       message,
       rank () over (partition by from_user_id, to_user_id order by id desc) rnk
from   table_name
) t1 where rnk = 1

这是假设 id 列是顺序生成的数字,所以 id 3 的消息是在 id 2 的消息之后创建的。通常,如果你有一个时间戳列,它会更合乎逻辑。在这种情况下,您可以使用order by timestamp desc

【讨论】:

  • 我试过你的版本,但它返回:错误:FROM 中的子查询必须有别名 LINE 1: SELECT * FROM (
  • 对不起,我习惯了 Oracle 语法...更新了我的查询以包含内部查询的别名
【解决方案3】:

Postgres 提供distinct on,这通常是解决此类问题的最佳方法:

select distinct on (to_user_id) m.*
from messages m
where m.from_user_id = 1
order by to_user_id, id desc;

【讨论】:

  • 哇。这真的很有帮助。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-12-28
  • 2017-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多