基于最大列值筛选Oracle SQL:获取B唯一且A为最大值的行
嘿,我明白你要做的事了——从Table1里提取每个B分组对应的唯一行,而且这行得是该分组里A值最大的那条。根据你的示例,我假设A字段是可以直接比较大小的(如果是像a_0这种字符串,后面我会补充处理方式),下面给你几种实用的解决方案:
方法1:用窗口函数ROW_NUMBER()(最直观)
这种方法先给每个B分组内的行按A降序排个号,然后挑出排名第一的行:
SELECT id, A, B FROM ( SELECT id, A, B, -- 按B分组,每组内按A降序排名 ROW_NUMBER() OVER (PARTITION BY B ORDER BY A DESC) AS row_rank FROM Table1 ) ranked_data WHERE row_rank = 1;
小提示:如果同一个B分组里有多个行的A值都是最大值,ROW_NUMBER()会随机选其中一行;要是想保留所有这些最大值行,把ROW_NUMBER()换成RANK()或者DENSE_RANK()就行。
方法2:聚合函数MAX()关联查询
先分组算出每个B对应的最大A值,再和原表关联找到对应的完整行:
SELECT t1.id, t1.A, t1.B FROM Table1 t1 INNER JOIN ( -- 先拿到每个B的最大A SELECT B, MAX(A) AS max_A_value FROM Table1 GROUP BY B ) group_max ON t1.B = group_max.B AND t1.A = group_max.max_A_value;
说明:这种方法如果遇到同一B下多个行A值相同且都是最大值,会返回所有这些行;如果要强制只返回一行,可以再加个条件,比如取id最小的,改成INNER JOIN (...) group_max ON ... AND t1.id = (SELECT MIN(id) FROM Table1 WHERE B = group_max.B AND A = group_max.max_A_value)。
方法3:Oracle专属的KEEP子句
Oracle有个特有的KEEP子句,能直接在聚合时获取对应最值的其他列,写法更简洁:
SELECT -- 取A最大的行中id最小的那个 MIN(id) KEEP (DENSE_RANK LAST ORDER BY A) AS id, MAX(A) AS A, B FROM Table1 GROUP BY B;
解释:DENSE_RANK LAST ORDER BY A表示定位到每个B分组里A最大的那些行,然后用MIN(id)从中选id最小的一行;要是想选id最大的,把MIN(id)换成MAX(id)就好。
特殊情况处理:如果A是带后缀的字符串
要是你的A是像a_0、a_1这种字符串,直接按A排序可能不会按数字后缀大小来(比如a_10会排在a_2前面),这时候得提取数字部分来排序,比如修改窗口函数的排序条件:
ROW_NUMBER() OVER (PARTITION BY B ORDER BY TO_NUMBER(SUBSTR(A, 2)) DESC) AS row_rank
这里SUBSTR(A, 2)提取从第2位开始的字符串(也就是_0里的0),再转成数字来排序,这样就能正确按后缀数字的大小判断最大值了。
内容的提问来源于stack exchange,提问作者John Asina

