从oracle中为每个组选择最新行

时间:2016-11-03 14:45:17

标签: sql oracle greatest-n-per-group

我在留言簿中有一个包含用户评论的表格。列是:id,user_id,title,comment,timestamp。

我需要为每个用户选择最新的行。 我尝试使用group by但是没有管理它,因为我无法在同一个查询中选择其他任何我按user_id分组的内容:

SELECT user_id, MAX(ts) FROM comments GROUP BY user_id

例如在这个查询中我不能添加也选择列id,tilte和comment。怎么办呢?

3 个答案:

答案 0 :(得分:6)

您可以使用JOIN

构建查询
select c.*
from comments c join
     (select user_id, max(ts) as maxts
      from comments c2
      group by user_id
     ) cc
     on c.user_id = cc.user_id and c.ts = cc.maxts;

还有其他方法。典型的建议是使用row_number()

select t.*
from (select c.*, row_number() over (partition by user_id order by ts desc) as seqnum
      from comments c
     ) c
where seqnum = 1;

这两个查询略有不同。如果用户的最新评论具有完全相同的ts,则第一个将返回重复项。第二个为每个用户返回一行。

答案 1 :(得分:6)

您可以使用分析函数

SELECT *
  FROM (SELECT c.*,
               rank() over (partition by user_id order by ts desc) rnk
          FROM comments c)
 WHERE rnk = 1

根据您要处理关系的方式(如果有两行具有相同的user_idts),您可能需要使用row_number或{{1} }而不是dense_rank。如果存在平局,rank将允许多行为第一行。如果存在平局,rank会随意返回一行。对于首先绑定的行,row_number的行为类似dense_rank,但假设两行首先绑定,则将下一行视为第二行而不是第三行。

答案 2 :(得分:3)

使用dense rank first/last函数

,这类问题有一个非常简单且非常有效的解决方案
select id,
       max(user_id) keep (dense_rank last order by ts) over (partition by id) as user_id,
       max(title)   keep (dense_rank last order by ts) over (partition by id) as title,
       max(comment) keep (dense_rank last order by ts) over (partition by id) as comment,
       max(ts)                                                                as ts
from   comments;