在SQL中,ROW_NUMBER()、RANK()和DENSE_RANK()这三个排名函数虽然语法相似,但行为差异显著。选错一个,结果可能完全偏离预期。核心区别在于:ROW_NUMBER()为每一行赋予唯一序号,即使排序值重复也强制编号;RANK()对相同值给予相同排名,但会跳过后续名次;DENSE_RANK()则连续编号,不跳过任何数字。三者都依赖于OVER(ORDER BY...)子句,具体选择取决于业务是否需要保留并列排名语义。

ROW_NUMBER() 为每行强制分配唯一序号,即使排序值相同
该函数具有“唯一性”特点——无论排序字段值是否重复,它都会按照ORDER BY指定的顺序从1开始连续编号。例如,若两条记录的salary均为8000,ROW_NUMBER()仍会分别返回2和3。这不是错误,而是其设计初衷:生成唯一的行序号。
- 必须配合
OVER()使用,且ORDER BY为必选项;若省略PARTITION BY,则对全表进行编号 - 常用于实现分页(如
WHERE rn BETWEEN 11 AND 20)或获取每组最新记录(如WHERE rn = 1) - 当排序字段存在重复值时,结果可能不稳定——建议在
ORDER BY后附加唯一列(如id)以确保确定性
RANK() 对相同值赋予相同排名,并跳过后续名次
当出现并列值时,RANK()不会压缩排名位置。例如,若有两个并列第2名,则下一个排名为第4名,第3名被跳过。这种机制符合体育比赛、考试成绩排名等现实场景——并列第二之后不会出现第三名。
- 同样依赖于
OVER(ORDER BY ...)子句,语法结构与ROW_NUMBER()完全相同 - 适用于“查询所有最高分员工”等场景——使用
WHERE rk = 1即可获取全部并列第一的记录 - 注意:跳号现象仅在存在重复值时出现;若所有排序字段值均唯一,则
RANK()与ROW_NUMBER()的输出结果一致
选哪个?核心在于是否保留并列排名语义
这不是性能或兼容性问题,而是业务意图判断:
- 需要唯一行号、实现分页或去重取首条记录 → 使用
ROW_NUMBER() - 需要真实反映“并列第N名”、允许同名次出现多行 → 使用
RANK() - 如果认为
RANK()的跳号过于跳跃(例如希望并列第2名之后紧跟第3名),则应改用DENSE_RANK()
容易被忽视的是,这三个函数在语法上几乎完全一致,仅靠函数名区分。一旦误用,结果偏差往往不易察觉,直到上线后查询数据才发现“少了并列记录”或“分页错位”等问题。因此,在编写SQL之前,务必明确业务需求。
