如何获得多列之间的 2 个最大值?

Posted

技术标签:

【中文标题】如何获得多列之间的 2 个最大值?【英文标题】:How to get the 2 greatest values between multiple columns? 【发布时间】:2017-04-14 19:03:52 【问题描述】:

我试图弄清楚如何从 5 个字段中获取 2 个最高值。 greatest函数我知道,但我也不知道如何提取第二高的值。

基本上,该表有 5 个NUMBER 类型的字段。在这个例子中,最后两列是我想要的结果。

| Score1 | Score2 | Score3 | Score4 | Score5 | | Highest1_value | Highest2_value 
+--------+--------+--------+--------+--------+ +----------------+---------------
|    10  |    20  |    30  |    40  |   50   | |       50       |       40
|    20  |    20  |    12  |    17  |    0   | |       20       |       20
|     7  |     7  |     7  |     7  |   11.1 | |       11.1     |        7
|    10  |    10  |    10  |    10  |   10   | |       10       |       10

【问题讨论】:

每一行都有一个标识符吗? 我猜在第二行中,highest2_value 应该是 17.. 对吗? vkp,是的,我有唯一的 ID。 Teja,No,Score1 和 Score2 都有 20,所以它们是最高的数字 预期的输出应该是什么样子?请将其发布为格式化文本。 【参考方案1】:

取消透视数据并使用row_number 获取每个 id 的前 2 个最高分。

select id
,max(case when rnum=1 then val end) as highest_1
,max(case when rnum=2 then val end) as highest_2
from (select id,score,val,row_number() over(partition by id order by val desc) as rnum
      from (select * from t --replace this with your tablename
            unpivot (val for score in (score1,score2,score3,score4,score5)) p
          ) tbl
      ) tbl
group by id

【讨论】:

其他数据库中没有unpivot就不行吗?可能在mysql里? 您可以直接使用greatestleast 获得maxmin,而无需取消透视(在MySQL 中)。因为 OP 需要 2 个最大值,所以我想不出不使用 row_number 的方法。 这仅返回来自 Score4 和 Score5 字段的值? 排序必须在val 字段而不是row_number 中的score。我改变了它,现在应该可以按预期工作了。 现在可以了,我接受这个答案,因为这是第一个。谢谢大家【参考方案2】:

如果我理解正确,你需要这个:

select your_table.*, REGEXP_SUBSTR(h.str, '^[^\-]+') AS h1, REGEXP_SUBSTR(h.str, '[^\-]+$') AS h2  FROM your_table
inner join  (
    select id, listagg(sc, '-') WITHIN GROUP (ORDER BY sc DESC) str FROM(
        select id, sc, row_number() over(partition by id order by sc desc) rn from (
            select id, sc FROM your_table
            UNPIVOT (sc for col in (Score1, Score2, Score3, Score4, Score5))
        ) tt
    )ttt
    where rn <= 2
    GROUP BY id
) h
ON your_table.id =  h.id

【讨论】:

在我看来,这个问题的正则表达式是矫枉过正。 @vkp - 当然也可以对 instr 和 substring 做同样的事情,只是正则表达式是我脑海中出现的最快的东西【参考方案3】:

这个解决方案避免了反透视,只是大量的剪切&粘贴&修改:

SELECT 
   dt.*,
   CASE maxscore -- GREATEST on all but the highest value,
                 -- simplified to a "Valued Case" based on mathguy's comment
      WHEN score1 THEN Greatest(score2, score3, score4, score5)
      WHEN score2 THEN Greatest(score1, score3, score4, score5)
      WHEN score3 THEN Greatest(score1, score2, score4, score5)
      WHEN score4 THEN Greatest(score1, score2, score3, score5)
      ELSE Greatest(score1, score2, score3, score4)
   END
FROM
 (
   SELECT t.*,
      Greatest(Score1,Score2,Score3,Score4,Score5) AS maxscore
   FROM tab t
 ) dt

基于@vkp 和@mathguy 的没有派生表/内联视图的cmets:

SELECT 
   t.*,
   Greatest(Score1,Score2,Score3,Score4,Score5) as Highest1_value,
   CASE Greatest(Score1,Score2,Score3,Score4,Score5)-- GREATEST on all but the highest value
      WHEN score1 THEN Greatest(       score2,score3,score4,score5)
      WHEN score2 THEN Greatest(score1,       score3,score4,score5)
      WHEN score3 THEN Greatest(score1,score2,       score4,score5)
      WHEN score4 THEN Greatest(score1,score2,score3,       score5)
      ELSE             Greatest(       score1,score2,score3,score4)
   END as Highest2_value
FROM tab t

【讨论】:

为什么要进行maxscore 计算?您可以将其包含在 case 表达式本身中。 这可以进一步简化。像这样编写case 表达式:case greatest(score1,...,score5) when score1 then ... when score2 then...(使其成为“简单”案例表达式,而不是“搜索”案例表达式;您不需要重复外部 greatest(...),因为它将在“左侧”)。

以上是关于如何获得多列之间的 2 个最大值?的主要内容,如果未能解决你的问题,请参考以下文章

分组多列时如何选择最大值或最后一条记录? [复制]

如何找到树上一组节点之间的最大距离?

mysql - 从多列中获取两个最大值

如何获得两个数字之间的最大素数并将它们存储在数组中?

在EXCEL如何在同一表格多列名称中查找数据相对应的名称

具有多列的熊猫每组的最大值/为啥它仅在展平时才有效?