rank适用于需并列排名且跳过后续序号的场景(如体育颁奖:两个第2名后直接第4名);dense_rank用于并列不跳号(两个第2名后为第3名);row_number强制唯一连续编号,适合去重筛选。

RANK、DENSE_RANK、ROW_NUMBER 这三个函数在 Oracle 19c 中行为稳定、语法一致,不需要额外启用特性 —— 直接用就行。关键不是“能不能用”,而是“选哪个、怎么写、哪里会翻车”。
什么时候该用 RANK 而不是 DENSE_RANK
当业务明确要求“并列名次后跳过后续序号”时才用 RANK。比如体育比赛颁奖:两个第二名,第三名直接空缺,下一个是第四名。
常见误用场景是做 Top N 筛选时混用 RANK 和 WHERE rank —— 如果前 3 名里有并列,<code>RANK 可能返回 5 条甚至更多记录(例如:1,1,1,4,4,6),而你本意只想取“实际排位 ≤3 的人”。
此时应改用 DENSE_RANK:DENSE_RANK() OVER (ORDER BY score DESC) 对三个 95 分返回 1,1,1,紧接着 92 分就是 2,不会跳空。
ROW_NUMBER 的唯一性陷阱
ROW_NUMBER 不处理重复值,它只按 ORDER BY 的物理顺序强行编号。哪怕 score 完全相同,也会给出 1,2,3…
这意味着:
– 结果不可复现(不同执行计划或数据块顺序变化会导致编号变动);
– 无法用于“取并列前三”的业务逻辑;
– 若未在 ORDER BY 中加入唯一键(如 ORDER BY score DESC, emp_id),同一语句多次执行可能返回不同行。
建议:仅在需要绝对唯一行号(如分页、抽样)且不关心业务语义时使用;否则优先补唯一排序字段。
分区排名(PARTITION BY)必须配 ORDER BY
RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) 是合法的;RANK() OVER (PARTITION BY dept_id) 会报错 ORA-30483:missing ORDER BY expression。
注意:
– PARTITION BY 不等于 GROUP BY,它不聚合,只是划窗;
– 每个分区内独立计数,所以不同部门的 “第1名” 可能工资相差很大;
– 如果漏写 ORDER BY,Oracle 19c 不会退化为默认排序,而是直接拒绝执行。
NULL 值排序方向容易被忽略
默认情况下,ORDER BY salary DESC 把 NULL 排在最前面(因为 Oracle 视 NULL 为“最大”)。如果想让 NULL 排末尾,必须显式写:ORDER BY salary DESC NULLS LAST。
否则会出现:明明某人没填工资,却排在所有有值的人前面,导致 RANK 结果严重失真。
这个细节在跨库迁移(比如从 MySQL 迁来)或前端展示时尤其容易出问题——前端以为“最高分在前”,结果看到一堆空值顶格显示。











