RANK() 会把相同分数的人排成并列并跳过后续名次,因其设计逻辑就是“并列则同名次,名次跳过”,如分数95、95、87返回1、1、3,与DENSE_RANK()和ROW_NUMBER()的语义本质不同。

为什么 RANK() 会把相同分数的人排成并列,还跳过后续名次
RANK() 的设计逻辑就是“并列则同名次,名次跳过”。比如三个人分数是 95, 95, 87,RANK() 返回的是 1, 1, 3 —— 不是 1, 1, 2。这是它和 DENSE_RANK() 的根本区别,不是 bug,是行为预期。
常见错误是误以为它该连续编号,结果发现中间缺了 2,然后去查文档、改写法,其实只是没选对函数。
- 适用场景:榜单展示强调“段位感”,比如“两人并列第一,第三名是唯一第二名”这种语义
- 不适用场景:需要连续序号的分页、导出 Excel 行号、做数组下标映射
-
RANK()必须配合OVER(ORDER BY ...)使用,单独写RANK()会报错ERROR 1064
怎么写一个带并列处理的学生成绩排名 SQL
假设表 student_scores 有字段 name、subject、score,要按科目分组、分数降序排并列名次:
SELECT name, subject, score, RANK() OVER (PARTITION BY subject ORDER BY score DESC) AS rank_num FROM student_scores;
关键点:
-
PARTITION BY subject是分组依据,不加就全表统一排序 -
ORDER BY score DESC决定高低顺序,漏掉DESC默认升序,最低分反而得1 - 如果想按多个字段排序(比如先比分数,分数一样再按提交时间早优先),写成
ORDER BY score DESC, submit_time ASC
RANK() 和 DENSE_RANK()、ROW_NUMBER() 混用时的坑
三者在同一查询里混用但没理清逻辑,容易导致业务含义混乱。比如导出数据时用 RANK() 显示“名次”,又用 ROW_NUMBER() 做“行号”,结果两个数字对不上,前端渲染错乱。
-
RANK():并列 → 同名次 → 跳号(1,1,3,4) -
DENSE_RANK():并列 → 同名次 → 不跳号(1,1,2,3) -
ROW_NUMBER():严格按顺序编号,哪怕分数相同也不同号(1,2,3,4) - 性能上三者几乎无差别,MySQL 8.0+ 窗口函数优化后,
ORDER BY字段有索引时执行很快
ORDER BY 字段缺失或类型不匹配导致 RANK() 结果异常
最隐蔽的问题:score 是 VARCHAR 类型存的数字,比如 '100'、'9'、'87',ORDER BY score DESC 会按字符串排序,结果变成 '9', '87', '100',RANK() 自然跟着错。
- 检查字段类型:
DESCRIBE student_scores;确认score是INT或DECIMAL - 临时修复(不推荐长期用):
ORDER BY CAST(score AS SIGNED) DESC - 排序字段含
NULL时,默认排在最前(ASC)或最后(DESC),影响并列判断,必要时用ORDER BY score DESC NULLS LAST(MySQL 8.0.22+ 支持)
真正麻烦的不是语法写错,而是排名逻辑和业务预期不一致——比如运营说“并列第一之后必须是第二名”,那你就不能用 RANK(),得换 DENSE_RANK()。函数本身很稳,踩坑都在语义理解那一层。


















