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

Posted

技术标签:

【中文标题】从 oracle 中为每个组选择最新行【英文标题】:Select latest row for each group from oracle 【发布时间】:2017-03-17 05:09:03 【问题描述】:

我在留言簿中有一张包含用户 cmets 的表格。列是:id、user_id、title、comment、timestamp。

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

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

例如,在这个查询中,我不能添加到还选择列 id、tilte 和 comment。如何做到这一点?

【问题讨论】:

【参考方案1】:

您可以使用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,则第一个将返回重复项。第二个返回每个用户一行。

【讨论】:

【参考方案2】:

您可以使用分析函数

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

根据您希望如何处理平局(如果可以有两行具有相同的user_idts),您可能需要使用row_numberdense_rank 函数而不是rank。如果有平局,rank 将允许多行排在第一位。 row_number 如果出现平局,将任意返回一行。 dense_rank 对于并列第一行的行为类似于 rank,但会认为下一行是第二行而不是第三行,假设两行并列第一。

【讨论】:

【参考方案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;

【讨论】:

以上是关于从 oracle 中为每个组选择最新行的主要内容,如果未能解决你的问题,请参考以下文章

从Oracle SQL中的每个组中选择具有最大值的行[重复]

使用 Spark Scala 为数据中的每个组选择窗口操作后的最新时间戳记录

在 ms Access 中从每个组中选择至少 3 行时出错 - 仅选择了至少 2 行

从每个组中选择1行匹配或回退

使用排序选择组中的最新记录

如何在 Oracle SQL 中不使用 distinct 选择从多个 max(case when) 派生的唯一行