RANK()实现并列排名且跳过空缺名次,如1,1,3,4;其原理是“严格大于当前值的行数+1”,必须配合OVER(ORDER BY ...)使用,不支持GROUP BY混用,且MySQL 8.0+才支持。

RANK() 就是干这个的,它天然支持不连续排名。只要分数相同,就给相同名次,后面名次直接跳过空缺——比如两个 95 分并列第 1,下一个 92 分就是第 3 名,中间没有第 2 名。
为什么 RANK() 会跳号?原理很简单
它的计算逻辑是:当前行的排名 = 当前行之前(含自身)有多少个“严格大于”当前值的行数 + 1。当多个值相等时,“大于”它们的行数一致,所以排名相同;而下一个更小的值,前面已经存在多个更大值,自然就跳过了中间数字。
这和 ROW_NUMBER()(纯递增编号)和 DENSE_RANK()(并列但不跳)有本质区别。
-
RANK():相同值 → 同名次 → 后续名次跳空(如 1,1,3,4) -
DENSE_RANK():相同值 → 同名次 → 后续名次紧接(如 1,1,2,3) -
ROW_NUMBER():不管值是否相同 → 每行唯一序号(如 1,2,3,4)
RANK() 必须带 OVER,且 ORDER BY 不可省略
RANK() 是窗口函数,不能单独使用。漏掉 OVER 或其中的 ORDER BY 会直接报错:ERROR 1064 (42000): You have an error in your SQL syntax。
常见写法示例:
SELECT student_name, score, RANK() OVER (ORDER BY score DESC) AS ranking FROM student_scores;
注意点:
- 如果要按班级分组排名,必须加
PARTITION BY class_id -
ORDER BY方向影响结果:升序(ASC)下低分排前面,通常用DESC - 排序字段允许多列,比如
ORDER BY score DESC, exam_date ASC(同分时按考试时间早优先)
实际业务中容易踩的坑
很多人用 RANK() 却没得到预期“跳号”,问题往往出在数据或写法上:
- 误把
RANK()当聚合函数用,比如写成SELECT RANK(), ... FROM ... GROUP BY ...—— 这会报错,RANK()必须配合OVER,且不能和GROUP BY混用 - 排序字段有
NULL值,默认NULLS FIRST(MySQL 8.0.22+ 支持显式控制),可能让NULL成为第一名,干扰真实排名逻辑 - 想查“排名 = 2”的记录,但因为跳号导致根本没有第 2 名(比如数据是 100,100,90),这时
WHERE ranking = 2查不到结果,得改用子查询或判断范围 - 没注意 MySQL 版本:低于 8.0 的实例不支持
RANK(),强行执行会提示FUNCTION xxx.RANK does not exist
真正难的不是写出语法,而是想清楚“要不要跳号”——这取决于业务规则。比如奖学金评定常要求“同分同名、后续顺延”,那就该用 DENSE_RANK();而体育比赛奖牌榜必须体现“并列金牌后是铜牌”,RANK() 才是正确选择。











