rank()更适合并列排名,因其对相同值赋予相同名次并跳过后续名次(如95、95、90→1、1、3),真实体现“同分同名”语义;而row_number()强制连续编号(1、2、3),丢失并列关系,无法满足成绩单、竞赛榜单等业务需求。

为什么RANK() OVER比ROW_NUMBER()更适合并列排名?
因为 RANK() 遇到相同值会跳过后续名次,而 ROW_NUMBER() 强制连续编号。比如两个考生都考了95分,RANK() 给他们都是第1名,下一个90分的考生是第3名;ROW_NUMBER() 则会排成1、2、3,失去“并列”语义。
实际场景中,成绩单、竞赛榜单、绩效分级都要求体现“同分同名次”,这时必须用 RANK(),不能靠后期补逻辑修正。
RANK() OVER的ORDER BY必须写全,别漏掉NULL或重复字段
常见错误是只按分数排序:ORDER BY score DESC,结果发现同分考生名次乱跳——这是因为数据库在遇到相同 score 时,内部排序不稳定,可能每次执行结果不同。
解决办法是补一个唯一字段(如考生ID)做二级排序:
RANK() OVER (ORDER BY score DESC, student_id ASC)
这样既保证同分者并列,又让排序可重现。如果 score 允许为 NULL,还要明确 NULLS LAST(PostgreSQL)或用 COALESCE(score, -1)(MySQL/SQL Server)避免 NULL 被排到最前干扰名次。
和DENSE_RANK()的区别:跳不跳名次,得看业务规则
三名考生分数为 95、95、90,RANK() 给出的是 1、1、3;DENSE_RANK() 是 1、1、2。区别在于是否“压缩”被跳过的名次。
选哪个取决于规则:
- 学校成绩单、公务员考试总榜常用
RANK():强调“第1名有两人”,第3名就是真实顺位 - 内部绩效档位划分有时用
DENSE_RANK():只关心档位层级(A/B/C),不care中间空了几档 -
NTILE(4)完全不同,它强行把数据等分,不处理并列,别混用
WHERE里不能直接用RANK(),得套一层子查询或CTE
这条语句会报错:SELECT *, RANK() OVER (...) rnk FROM scores WHERE rnk ——因为窗口函数在 <code>WHERE 执行之后才计算。
正确写法只有两种:
用子查询:
SELECT * FROM ( SELECT *, RANK() OVER (ORDER BY score DESC) AS rnk FROM scores ) t WHERE t.rnk <p>或用 CTE(更易读):</p><pre class="brush:php;toolbar:false;">WITH ranked AS ( SELECT *, RANK() OVER (ORDER BY score DESC) AS rnk FROM scores ) SELECT * FROM ranked WHERE rnk <p>这个限制容易被忽略,尤其当想“取前N名”时直接写 <code>WHERE RANK() ,结果语法报错或逻辑错位。</code></p><p>真正麻烦的不是写法,而是当分数字段存在浮点误差(比如 <code>DECIMAL(5,2)</code> 存算术平均分)、或来自多表JOIN后聚合计算时,表面相同的分数可能因精度差异被拆成不同名次——这时候得先 <code>ROUND(score, 2)</code> 再排序,否则并列就失效了。</p>











