rank()在分组内仍跳号,因其设计规则为“并列同名次,后续名次=当前名次+并列行数”,该逻辑在每个partition内独立生效;如部门a薪资15000、15000、12000对应排名1、1、3,而非1、1、2。

RANK() 本身不处理“分组并列”,它只按你写的 PARTITION BY 和 ORDER BY 执行——并列行为是函数固有逻辑,不是可开关的选项。
为什么 RANK() 在分组里还是跳号?
RANK() 的跳号行为来自定义:相同排序值获得相同名次,后续名次 = 当前名次 + 并列行数。这个规则在每个 PARTITION 内独立生效,和是否分组无关。
- 比如部门 A 有三人薪资为 15000、15000、12000,RANK() 输出是
1、1、3(不是1、1、2) - 部门 B 有两人薪资为 18000、10000,输出是
1、2 - 跳号不是 bug,是设计;如果你要不跳号,该用
DENSE_RANK(),不是调参数
RANK() 必须搭配 OVER,不能和 GROUP BY 混用
常见报错 ORA-30483 或 Window function not allowed in GROUP BY 就是因为试图在聚合后直接开窗。
- 错误写法:
SELECT dept, RANK() OVER (ORDER BY SUM(salary)) FROM emp GROUP BY dept - 正确做法:先聚合,再对聚合结果开窗——用子查询或 CTE 包一层
- 示例:
SELECT dept, total_sal, RANK() OVER (ORDER BY total_sal DESC) AS rk FROM (SELECT dept, SUM(salary) AS total_sal FROM emp GROUP BY dept) t
- 注意:
RANK()是窗口函数,执行阶段晚于GROUP BY,不能出现在同一层级的 SELECT 中
PARTITION BY 字段含 NULL 时排名会乱吗?
会。PARTITION BY column 如果 column 有 NULL,不同数据库把 NULL 当作一个独立分区还是忽略,行为不一致。
- PostgreSQL 把 NULL 视为合法分区值,
PARTITION BY dept中 dept IS NULL 的行会被单独分到一组 - SQL Server 默认可能把 NULL 当作“无分组”,导致部分行被归入默认分区(全表),破坏分组意图
- 稳妥做法:提前清洗,或用
COALESCE(dept, 'unknown')替换 NULL,确保分区键可控
ORDER BY 里的 NULL 值怎么影响并列判断?
NULL 参与排序时,默认位置因数据库而异,直接影响谁和谁“并列”。
-
ORDER BY score DESC在 PostgreSQL 默认NULLS LAST,Oracle 也是;但 SQL Server 可能NULLS FIRST - 如果 score 字段有 NULL,且你没显式写
NULLS LAST,同一 SQL 在两边跑出来的RANK()结果可能完全不同 - 强制统一行为:
RANK() OVER (PARTITION BY dept ORDER BY score DESC NULLS LAST) - 别依赖隐式规则——只要字段可能为空,就显式声明
NULLS FIRST或NULLS LAST
真正卡住人的从来不是 RANK() 怎么写,而是 PARTITION BY 字段有没有 NULL、ORDER BY 字段有没有 NULL、以及你到底要不要跳号——这三个点没理清,光调函数名没用。











