Oracle 19C中基于多列优先级规则的分组单行筛选方法咨询
Oracle 19C: 分组后按多优先级规则筛选单行的简便实现
在Oracle 19C里处理这种分组后按多规则筛选唯一行的需求,最省心的方法就是用窗口函数ROW_NUMBER()搭配自定义排序逻辑,不用写一堆嵌套子查询,代码简洁还容易维护。咱们直接结合你的需求和示例数据来拆解:
核心思路
利用ROW_NUMBER()窗口函数,针对[NAME, DAY, PROD]分组,然后按照你指定的优先级给每组内的行排序,最后只取每组中排名为1的行即可。排序规则严格对应你的要求:
- 第一优先级:按
ABS(S)升序(绝对值最小的行排最前) - 第二优先级:按
AMT1降序(数值最大的行排最前) - 第三优先级:按
M升序(数值最小的行排最前) - 第四优先级:按
P升序(数值最小的行排最前)
完整SQL代码
SELECT t.NAME, t.DAY, t.PROD, t.S, t.M, t.P, t.AMT1, t.AMT2, t.AMT3 FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY NAME, DAY, PROD ORDER BY ABS(S) ASC, AMT1 DESC, M ASC, P ASC ) AS rn FROM your_table_name ) t WHERE t.rn = 1;
代码解释
- PARTITION BY子句:指定分组字段
NAME, DAY, PROD,窗口函数会在每个分组内独立计算排名。 - ORDER BY子句:完全匹配你的优先级规则:
ABS(S) ASC:先找绝对值最小的SAMT1 DESC:S绝对值相同时,取AMT1最大的M ASC:前两个条件都相同时,取M最小的P ASC:最后如果还有重复,取P最小的
- 外层筛选:只保留每组中
rn=1的行,也就是每组按规则筛选出来的唯一行。
示例验证
拿你给出的MANGO分组示例数据来说:
| NAME | DAY | PROD | S | M | P | AMT1 | AMT2 | AMT3 |
|---|---|---|---|---|---|---|---|---|
| MANGO | 1 | 1 | -2.75 | 3 | 15 | 21.277 | 80 | 80 |
| MANGO | 1 | 1 | -2.75 | 1.5 | 21 | 27.778 | 80 | 80 |
| MANGO | 1 | 1 | -2.75 | 3 | 21 | 27.778 | 80 | 80 |
| MANGO | 1 | 1 | -2.75 | 3 | 14 | 20 | 80 | 80 |
分组内所有行的ABS(S)都是2.75,所以进入第二优先级AMT1 DESC,此时第2、3行的AMT1最大(27.778);接着看第三优先级M ASC,第2行的M是1.5,比第3行的3小,所以第2行的rn=1,最终会被筛选出来,完全符合你的预期。
再看你补充的几个示例:
- APPLE 1-1分组:所有行
ABS(S)最小的是-2.5(绝对值2.5),直接被选中 - APPLE 8-0.5分组:在
ABS(S)相同的情况下,AMT1最大的51.02对应的行被选中 - MANGO 5-1分组:前面条件都相同时,P最小的14对应的行被选中
补充说明
如果你的需求里允许并列排名(比如多个行完全符合所有优先级规则时保留多行),可以把ROW_NUMBER()换成RANK()或者DENSE_RANK(),但根据你的描述,需要每组唯一一行,所以ROW_NUMBER()是最合适的。
内容的提问来源于stack exchange,提问作者Divya
相关产品推荐
相关产品推荐

