ROW_NUMBER()是行序分配器而非排名函数,按ORDER BY硬编1、2、3……不跳号不并列;缺决胜字段则结果不可复现;取最高分需用RANK()/DENSE_RANK()保并列;WHERE中不可直接用rn别名,须子查询或CTE。

ROW_NUMBER() 本质是行序分配器,不是排名函数
它不比较值是否相等,只按 ORDER BY 指定的逻辑顺序逐行硬编 1、2、3……哪怕两行 score = 95 完全一样,只要在排序结果中一前一后,就会得到 rn = 1 和 rn = 2。这不是 bug,是设计契约:必须返回唯一整数,且不跳号、不并列。
ORDER BY 缺乏决胜字段时,结果不可复现
当 ORDER BY score DESC 遇到多个相同 score,数据库没有义务保持这些行之间的相对顺序。不同执行计划、并发写入、甚至查询时间点微小差异,都可能导致同一批数据每次 ROW_NUMBER() 分配结果不同。
- 快速验证:运行
SELECT COUNT(*) FROM t GROUP BY score HAVING COUNT(*) > 1,看是否有重复分值 - 稳定写法必须补唯一字段:如
ORDER BY score DESC, id ASC(id是主键或能打破平局的列) - 别依赖
created_at这类高并发易撞车的时间戳——毫秒级也挡不住事务提交顺序差异
误用 ROW_NUMBER() 做“取最高分”会漏数据
想查“每个部门分数最高的员工”,若写 ROW_NUMBER() OVER (PARTITION BY dept ORDER BY score DESC) 再 WHERE rn = 1,结果只返回一个,哪怕两个员工都是 95 分——因为 rn 强制唯一,它选了其中一个,另一个被无声过滤掉。
- 要保留并列,必须换函数:
RANK()或DENSE_RANK() -
RANK()对相同score都给1,下一个不同值跳号(如 90 分得3);DENSE_RANK()则给2 - 两者都需配合
WHERE rn = 1才能取全并列最高者,但注意:它们返回的是“名次”,不是“行号”
WHERE 中不能直接用 rn 别名,这是执行顺序问题
ROW_NUMBER() 在 SQL 执行流程中属于“窗口计算阶段”,晚于 WHERE。所以 WHERE rn = 1 一定会报错,比如 Unknown column 'rn' 或语法拒绝。
- 正确做法只有两种:
SELECT * FROM (SELECT *, ROW_NUMBER() OVER (...) AS rn FROM t) t2 WHERE t2.rn = 1,或用WITH ranked AS (...)CTE - 别名不能是
rank、row_number这类保留字,某些方言(如 Hive)会解析冲突 - CTE 不仅可读性好,还能避免多层嵌套子查询带来的优化器困惑
真正容易被忽略的点在于:你写的 ORDER BY 是否真的能保证每行位置唯一? 很多人加了 id 却忘了它可能为 NULL,或没意识到 PARTITION BY 字段本身含大量 NULL——这时所有 NULL 会被归为同一组,编号逻辑就已偏离业务预期。










