查找每组其他行的最大值

Posted

技术标签:

【中文标题】查找每组其他行的最大值【英文标题】:Find Maximal Value of other Rows per Group 【发布时间】:2017-04-16 10:28:20 【问题描述】:

我有一个简单的表格,其中包含分组 (GRP_ID) 中的值 (ID)。

create table tst as
select 1 grp_id, 1 id from dual union all
select 1 grp_id, 1 id from dual union all
select 1 grp_id, 2 id from dual union all
select 2 grp_id, 1 id from dual union all
select 2 grp_id, 2 id from dual union all
select 2 grp_id, 2 id from dual union all
select 3 grp_id, 3 id from dual; 

使用分析函数很容易找到每个组的最大值。

select grp_id, id,
max(id) over (partition by grp_id) max_grp
from tst
order by 1,2;

    GRP_ID         ID    MAX_GRP
---------- ---------- ----------
         1          1          2 
         1          1          2 
         1          2          2 
         2          1          2 
         2          2          2 
         2          2          2 
         3          3          3 

但目标是找到不包括当前行的值的最大值。

这是预期的结果(MAX_OTHER_ID 列):

   GRP_ID         ID    MAX_GRP MAX_OTHER_ID
---------- ---------- ---------- ------------
         1          1          2            2 
         1          1          2            2 
         1          2          2            1 
         2          1          2            2 
         2          2          2            2  
         2          2          2            2 
         3          3          3              

请注意,在 GRP_ID = 2 中存在与 MAX 值的关系,因此 MAX_OTHER_ID 保持不变。

我确实管理了这两个步骤的解决方案,但我想知道是否有更直接和简单的解决方案。

with max1 as (
select grp_id, id,
row_number() over (partition by grp_id order by id desc) rn
from tst
)
select GRP_ID, ID, 
case when rn = 1 /* MAX row per group */ then
  max(decode(rn,1,to_number(null),id)) over (partition by grp_id)
else
   max(id) over (partition by grp_id)
end as max_other_id   
from max1
order by 1,2

;

【问题讨论】:

【参考方案1】:

我希望窗口函数支持多个范围规范,例如:

max(id) over (
        partition by grp_id 
        order by id 
        range between unbounded preceding and 1 preceding
        or range between 1 following and unbounded following
        )

但不幸的是他们没有。

作为一种解决方法,您可以避免子查询和 CTE 在不同范围内使用该函数两次,然后调用 coalesce

select grp_id,
    id,
    coalesce(
            max(id) over (
                partition by grp_id
                order by id 
                range between 1 following and unbounded following
                )
            , max(id) over (
                partition by grp_id 
                order by id 
                range between unbounded preceding and 1 preceding
                )
            ) max_grp
from tst
order by 1,
    2

Coalesce 开箱即用,因为窗口函数调用的结果将是给定窗口中的最大值或空值。

演示 - http://rextester.com/SDXVF13962

【讨论】:

完美解决方案。我被困了一段时间,正要告诉 OP 它不能在单个查询中完成。这就是 SO 的美妙之处,你总能学到新东西。 正面IDs的好解决方案。 @MarmiteBomber - 我认为是的。 @GurV 能否以某种方式解除此限制,以提供负数的解决方案? @MarmiteBomber - 更新了答案。请检查【参考方案2】:
SELECT GRP_ID,ID, (SELECT Max(ID)  FROM TEST A WHERE A.ROWID<>B.ROWID AND A.GRP_ID=B.GRP_ID) maX_ID FROM TEST B;

通过 Co-Related Query 获得了预期的结果!希望这会有所帮助。

【讨论】:

以上是关于查找每组其他行的最大值的主要内容,如果未能解决你的问题,请参考以下文章

SQL:查找每组的最大记录[重复]

MySQL按顺序查找每组最近/最大的记录

在根据最大列值理解行的同时查找具有最高值的行的列名

在 csv 文件中查找行的最大值,同时排除 pyspark 中的标题

在 Pandas、Python 中查找具有相同第一列的所有行的最小值、最大值、平均值

在排除某些行的矩阵的列中查找最大元素