【问题标题】:Return row with the max value of one column per group [duplicate]返回每组一列最大值的行[重复]
【发布时间】:2012-05-07 17:11:13
【问题描述】:

如果不搜索同一个表至少两次以获取最大行,然后获取该行的值,我很难做到这一点。有问题的桌子很大,所以这是不可接受的。

这是我的桌子的样子:

SCORES
ID    ROUND    SCORE
1     1        3
1     2        6
1     3        2
2     1        10
2     2        12
3     1        6

我需要返回每个 ID 在最近一轮中获得的分数。即最大(轮次)的行,但不是最大分数的行。

OUTPUT:
ID   ROUND   SCORE
1    3       2
2    2       12
3    1       6

现在我有:

SELECT * FROM 
(SELECT id, round,
CASE WHEN (MAX(round) OVER (PARTITION BY id)) = round THEN score ELSE NULL END score
 FROM
 SCORES
 where id in (1,2,3)
) scorevals
WHERE
scorevals.round is not null;

这可行,但效率很低(我必须手动过滤掉所有这些行,而我一开始就不能抓取这些行。)

我可以做些什么来获得正确的价值观?

【问题讨论】:

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


    【解决方案1】:

    您使用分析函数走在正确的轨道上。但是您可能想要使用 rank 函数来实现类似的功能

    SELECT *
      FROM (SELECT a.*,
                   rank() over (partition by id order by round desc) rnk
              FROM scores
             WHERE id IN (1,2,3))
     WHERE rnk = 1
    

    如果可以存在关联(具有相同 idround 的行),您可能希望使用 row_number 分析函数而不是 rank-- 这将任意选择两个关联行之一将rnk 设为 1,而不是像 rank 那样返回两者。

    如果你想使用MAX 解析函数,你也可以这样做

    SELECT *
      FROM (SELECT a.*,
                   MAX(round) OVER (partition by id) max_round
              FROM scores
             WHERE id IN (1,2,3))
     WHERE round = max_round
    

    【讨论】:

      【解决方案2】:

      没有子查询也是可以的:

      SELECT DISTINCT
             id
            ,max(round) OVER (PARTITION BY id) AS round
            ,first_value(score) OVER (PARTITION BY id ORDER BY round DESC) AS score
      FROM   SCORES
      WHERE  id IN (1,2,3)
      ORDER  BY id;
      

      准确返回您要求的内容。
      关键是DISTINCT 是在 窗口函数之后应用的。

      SQL Fiddle.

      也许更快,因为它两次使用同一个窗口:

      SELECT DISTINCT
             id
            ,first_value(round) OVER (PARTITION BY id ORDER BY round DESC) AS round
            ,first_value(score) OVER (PARTITION BY id ORDER BY round DESC) AS score
      FROM   SCORES
      WHERE  id IN (1,2,3)
      ORDER  BY id;
      

      否则做同样的事情。

      【讨论】:

        【解决方案3】:

        对于这类问题,我倾向于使用max...keep...dense_rank 构造:

        select
          id,
          max(round)  round,
          max(score) keep (dense_rank last order by round) score
        from
          tq84_scores
        group by
          id;
        

        sql fiddle

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-31
          • 2021-12-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多