如何获得第二大列值和列名

Posted

技术标签:

【中文标题】如何获得第二大列值和列名【英文标题】:How to get second largest column value and column name 【发布时间】:2020-08-27 16:25:07 【问题描述】:

如何获得第二大列的值及其名称?

我当前的查询给出的结果大部分是正确的,但在最大值和第二大值相同的情况下,我得到的值是错误的。

    select item_code, A, B, C, 
        greatest(A, B, C) as largest1, 
        greatest(case when largest1 = A then 0 else A end,
                 case when largest1 = B then 0 else B end,
                 case when largest1 = C then 0 else C end) as largest2,
        (case largest1 when A then 'A'
                       when B then 'B'
                       when C then 'C' end) as largest1_column_name,
        (case largest2 when A then 'A'
                       when B then 'B'
                       when C then 'C' else 'None' end) as largest2_column_name 
        from table1 

下面是示例表:

+-----------+----+----+----+
| item_code | A  | B  | C  |
+-----------+----+----+----+
| p1        | 20 | 30 | 40 |
| p2        | 50 | 30 | 10 |
| p3        | 30 | 50 | 10 |
| p4        | 30 | 30 | 30 |
| p5        | 50 | 50 | 10 |
| p6        |  0 |  0 |  0 |
+-----------+----+----+----+

以下是预期输出:

+-----------+----+----+----+----------+----------+----------------------+----------------------+
| item_code | A  | B  | C  | largest1 | largest2 | largest1_column_name | largest2_column_name |
+-----------+----+----+----+----------+----------+----------------------+----------------------+
| p1        | 20 | 30 | 40 |       40 |       30 | C                    | B                    |
| p2        | 50 | 30 | 10 |       50 |       30 | A                    | B                    |
| p3        | 30 | 50 | 10 |       50 |       30 | B                    | A                    |
| p4        | 30 | 30 | 30 |       30 |       30 | A                    | B                    |
| p5        | 50 | 50 | 10 |       50 |       50 | A                    | B                    |
| p6        |  0 |  0 |  0 |        0 |        0 | A                    | B                    |
+-----------+----+----+----+----------+----------+----------------------+----------------------+

这是我从查询中得到的输出(我已将错误标记为评论):

+-----------+----+----+----+----------+-------------+----------------------+----------------------+
| item_code | A  | B  | C  | largest1 |  largest2   | largest1_column_name | largest2_column_name |
+-----------+----+----+----+----------+-------------+----------------------+----------------------+
| p1        | 20 | 30 | 40 |       40 | 30          | C                    | B                    |
| p2        | 50 | 30 | 10 |       50 | 30          | A                    | B                    |
| p3        | 30 | 50 | 10 |       50 | 30          | B                    | A                    |
| p4        | 30 | 30 | 30 |       30 | 0/*wrong*/  | A                    | NULL/*wrong*/        |
| p5        | 50 | 50 | 10 |       50 | 10/*wrong*/ | A                    | C/*wrong*/           |
| p6        |  0 |  0 |  0 |        0 | 0/*wrong*/  | A                    | A/*wrong*/           |
+-----------+----+----+----+----------+-------------+----------------------+----------------------+

【问题讨论】:

不要为数据和输出添加图像。它应该作为内联测试添加到问题中 那些错误的结果应该怎么办?我的意思是它应该显示什么? @Sujitmohanty30 我已经给出了预期的输出。在 maximum2 中,即使它等于最大值,它也应该是第二大值。这里 p4 应该是 30,但我得到的是 0。 如果出现平局,它选择哪一列真的很重要吗? 【参考方案1】:

我在 Snowflake 中尝试了一个轻微的变化(listagg 而不是string_agg),它似乎得到了预期的结果

with cte (item_code, abc, id) as
(select item_code, a, 'a' from table1 union all
 select item_code, b, 'b' from table1 union all
 select item_code, c, 'c' from table1)
 
select item_code, 
       max(case when id='a' then abc end) a,
       max(case when id='b' then abc end) b,
       max(case when id='c' then abc end) c,
       split_part(string_agg(abc::varchar,',' order by abc desc),',',1) largest1,
       split_part(string_agg(abc::varchar,',' order by abc desc),',',2) largest2,
       split_part(string_agg(id,',' order by abc desc),',',1) largest1_col,
       split_part(string_agg(id,',' order by abc desc),',',2) largest2_col
from cte
group by item_code;

【讨论】:

谢谢。是的,这种方法适用于 listagg。我只是将其更改如下: split_part((listagg(id, ',') within group (order by abc desc)),',',1) maximum1_col,【参考方案2】:

这可能会更简单地通过取消透视行、对值进行排名,然后使用条件聚合来实现。在 Postgres 中,您可以这样表述:

select t.*, x.*
from table1 t1
cross join lateral (
    select 
        min(val) filter(where rn = 1) largest1,
        min(val) filter(where rn = 2) largest2,
        min(col) filter(where rn = 1) largest1_column_name,
        min(col) filter(where rn = 2) largest2_column_name
    from (
        select x.*, dense_rank() over(order by val desc) rn
        from (values ('a', a), ('b', b), ('c', c)) as x(col, val)
    ) x
) x

【讨论】:

谢谢,我试过了,但我收到错误(无效操作:“select”处或附近的语法错误)。此错误出现在 select min(val) 位置。只是为了确认这种方法是否适用于红移?我在红移。我将 postgre 标记为通常 postgre 方法在 redshift 中有效。

以上是关于如何获得第二大列值和列名的主要内容,如果未能解决你的问题,请参考以下文章

当我们在 plsql 中动态传递列名的值和相应的列值时获取整行的存储过程

如何根据一个数据帧中的列值和R中另一个数据帧的列标题名称有条件地创建新列

如果您使用 pandas 数据框知道列值和行值,如何检索数据? [复制]

如何获取记录表格表具有不同的列值和相同的外键?

读取超大文件 R 的列名和列值

如何将数据框输出为文本(字符串)混合值和列名R