rank()一定跳号,因其按“不同更大值个数+1”并跳过已占名次,如[100,100,95,88]得1,1,3,4;dense_rank()则按不同值序号连续编号,得1,1,2,3,无跳号。

RANK() 一定会跳号,这不是 bug,是它设计的本意;要消除跳号,必须换用 DENSE_RANK(),不能靠改参数或加条件。
为什么 RANK() 明明并列却返回 1,1,3?
RANK() 的逻辑是:「当前值前面有多少个**不同的更大值** + 1」。比如分数为 [100, 100, 95, 88],两个 100 前面没有更大值 → 都是第 1 名;95 前面只有 100 这一种更大值 → 名次 = 1 + 1 = 2?不,RANK() 实际算的是「跳过已被并列占用的名次」,所以两个第 1 名后,下一名直接是第 3 名。
常见错误现象:
- 查“第 2 名学生”,
RANK()返回空 —— 因为根本没第 2 名 - 导出报表看到排名是
1, 1, 3, 4, 4, 6,误以为数据断层或排序错 - 用
WHERE rnk 想取 Top 3,结果只返回 4 行(含两个第 1 和一个第 3),但业务预期是“最多 3 人”
DENSE_RANK() 怎么做到不跳号?
DENSE_RANK() 的逻辑简单直接:「每遇到一个新值,名次就 +1;重复值复用上一个名次」。同样数据 [100, 100, 95, 88],它给出 1, 1, 2, 3。
注意几个关键点:
- 它不会合并行 ——
score = 100的两人仍各自占一行,dense_rank值都是 1 - 它适合需要固定档位数量的场景,比如“按销售额分 A/B/C 三档”,必须有且仅有三档
- 用
WHERE dense_rank 可能返回远超 2 行(如 10 人并列第 2 名 → 返回 12 行)
为什么 WHERE 里不能直接写 RANK() 或 DENSE_RANK()?
窗口函数在 SQL 执行顺序中晚于 WHERE,所以以下写法一定报错:
SELECT * FROM sales WHERE RANK() OVER (ORDER BY amount DESC) <p>正确做法只有两种:</p>
- 子查询嵌套:
SELECT * FROM (SELECT *, RANK() OVER (ORDER BY amount DESC) AS rnk FROM sales) t WHERE t.rnk - CTE 更清晰:
WITH ranked AS (SELECT *, DENSE_RANK() OVER (ORDER BY amount DESC) rnk FROM sales) SELECT * FROM ranked WHERE rnk
漏掉这层包裹,是新手最常踩的坑,报错信息通常是 Invalid use of window function 或字段不存在。
PARTITION BY 漏写会导致全表误排
想算“每个部门薪资前 2 的员工”,却只写 RANK() OVER (ORDER BY salary DESC),结果是全校/全公司统一排名,不是部门内排名。
必须显式加上分区:
RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC)-
PARTITION BY字段类型需与 SELECT 中一致,否则可能隐式转换失败 - 如果视图里用了
PARTITION BY subject,但 SELECT 列表没包含subject,多数数据库会报错或静默忽略分组
真正容易被忽略的是:跳不跳号本身不决定对错,而是由业务是否允许“空档”来驱动 —— 比如奥运奖牌榜必须跳号(金牌、银牌、铜牌),而内部绩效档位(S/A/B/C)必须连续。选错函数,过滤逻辑就彻底失效。











