RANK()的“跳级并列”行为指相同值获同一名次且后续名次跳过被占位数,如两个95分同为第1名,下一个90分直接排第3名;这区别于DENSE_RANK()的连续编号和ROW_NUMBER()的唯一序号。

什么是RANK函数的“跳级并列”行为
RANK() 在 SQL 中天然支持“跳级并列”——即相同分数得到相同名次,但下一个名次会跳过被并列占用的数量。比如两个 95 分都排第 1 名,下一个 90 分就是第 3 名,而不是第 2 名。
这和 DENSE_RANK()(不跳级)以及 ROW_NUMBER()(强制唯一序号)有本质区别。如果你的需求明确是“同分同名、名次不连续”,RANK() 就是直接解,无需额外逻辑。
RANK() 的基本写法与常见错误
核心是必须配合 OVER(ORDER BY ...) 子句,且不能单独出现在 SELECT 列表中(否则报错 Window function is missing OVER clause)。
- ✅ 正确写法:
SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rank_num FROM students; - ❌ 错误写法:
SELECT name, score, RANK(score) FROM students;(缺少OVER,语法非法) - ⚠️ 常见陷阱:用
ASC排序却期望高分排前面——成绩排名通常要ORDER BY score DESC - ⚠️ 多字段排序时未明确优先级,例如
ORDER BY score DESC, id ASC才能保证同分时按学号稳定排序
如何验证跳级是否生效
直接查出结果后观察名次序列是否出现空缺。例如输出如下:
name score rank_num Alice 95 1 Bob 95 1 Charlie 90 3 David 88 4
看到 rank_num 从 1 跳到 3,就说明跳级并列已生效。如果期望的是 1→1→2→3,则不该用 RANK(),该换 DENSE_RANK()。
注意:不同数据库对 NULL 的处理略有差异——多数将 NULL 视为最小值(DESC 下排最后),但 PostgreSQL 默认把 NULL 当最大值。如有 NULL 成绩,建议显式控制:ORDER BY score DESC NULLS LAST(PostgreSQL 支持,MySQL 8.0+ 不支持该子句,需用 COALESCE(score, -1) 替代)。
和 DENSE_RANK() 混用时的性能与语义风险
同一个查询里混用 RANK() 和 DENSE_RANK() 并不慢,窗口函数计算本身开销相近,但容易引发语义混淆——尤其当业务方只看列名 rank 却没注意是哪种实现。
- 命名建议:始终用明确别名,如
RANK() OVER (...) AS rank_skipped、DENSE_RANK() OVER (...) AS rank_dense - MySQL 8.0+、PostgreSQL、SQL Server、Oracle 都支持
RANK(),但 SQLite 目前(3.45 仍不支持) - 如果需要兼容老版本 MySQL(
跳级本身不是 bug,是设计特性;真正容易被忽略的是:它会让“前 N 名”这类条件变得不直观——比如取 rank_num 可能实际返回 4 人(因有两个并列第 1 名),这点在分页或奖励发放逻辑里必须提前对齐业务预期。

















