应使用 dense_rank() 实现并列不跳号排名,其按值分档计数,如95、95、92、90得1、1、2、3;而rank()按严格大于计数故必跳号;引用排名需子查询或cte,因窗口函数执行晚于where。

RANK() 不能解决“并列不跳号”——它天生就是跳号的。你要的是 DENSE_RANK()。
RANK() 为什么一定会跳号?
- 它的定义就是:当前行排名 = 严格大于当前值的行数 + 1
- 两个 95 分时,“严格大于 95”的行数都是 0,所以都得第 1 名
- 下一个 92 分,前面已有两行 > 92(那两个 95),所以是 2 + 1 = 第 3 名 → 中间空出第 2 名
这不是 bug,是设计行为。想“不跳号”,就不能用 RANK()。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
该用哪个函数?DENSE_RANK() 才是正解
- 同样处理并列,但逻辑是:“当前值是第几档”
- 95、95、92、90 → 排名是
1, 1, 2, 3,没有空档 - 语法完全一致,只换函数名:
SELECT name, score, DENSE_RANK() OVER (ORDER BY score DESC) AS ranking FROM student_scores;
- 分组内使用也一样,只改
PARTITION BY:
SELECT class_id, name, score,
DENSE_RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS class_rank
FROM student_scores;
常见误操作:在 WHERE 里直接引用排名别名
- 这会报错:
Unknown column 'ranking' - 因为窗口函数在 SQL 执行顺序中晚于
WHERE - 必须用子查询或 CTE:
SELECT * FROM ( SELECT name, score, DENSE_RANK() OVER (ORDER BY score DESC) AS ranking FROM student_scores ) t WHERE ranking <hr><h3>容易被忽略的细节:NULL 和排序稳定性</h3>
-
ORDER BY score DESC默认把NULL当最小值 → 排最后(符合直觉) - 但如果字段含大量
NULL,又没显式写NULLS LAST,某些 MySQL 模式下可能行为不一致 - 更稳妥的做法是提前过滤:
WHERE score IS NOT NULL - 多重排序防非确定性:比如同分时按
student_id ASC补充,避免每次查询结果顺序漂移
真正卡住人的,往往不是不会写 DENSE_RANK(),而是写对了却在 WHERE 里直接用、或让 NULL 悄悄混进排名第一档。










