RANK()跳名次(如1,1,3),DENSE_RANK()不跳(如1,1,2);二者均需OVER(ORDER BY),且不可在WHERE中直接引用,须用子查询或CTE过滤。

直接说结论:并列名次要不要跳号,不是写法问题,是业务语义选择——RANK() 跳号,DENSE_RANK() 不跳,两者都不能在 WHERE 中直接引用,必须用子查询或 CTE 过滤。
为什么 RANK() 会漏掉“第2名”这种直观结果
根本原因不是 bug,是定义使然:RANK() 计算的是“比当前值大的不同值个数 + 1”。比如分数为 [100, 100, 95, 88],两个 100 占了名次 1,95 前面只有一种更大值(100),但名次不是 2,而是 3 —— 因为名次 2 已被“占用”(逻辑上属于第一个唯一值之后的空档)。
常见错误现象:
- 查“销售额排名第 2 的产品”,用
RANK()返回空 —— 实际第 2 名被跳过了 - 导出报表发现排名序列是
1, 1, 3, 4, 4, 6,业务方问“怎么没有第 2 名和第 5 名?” - 做 Top 3 查询时,因并列导致只返回 2 行(比如两人并列第 1,第三人排第 3),误以为数据不全
DENSE_RANK() 怎么做到名次连续不跳
DENSE_RANK() 的逻辑更贴近直觉:按排序顺序扫一遍,每遇到一个**新值**就加 1,重复值复用刚分配的数字。对同样数据 [100, 100, 95, 88],它给出 1, 1, 2, 3。
关键提醒:
- 它不会合并行,
score = 95的那行 dense_rank 就是 2,独立存在 - 如果 10 人并列第 2 名,
WHERE dense_rank 会返回 11 行(2 个第 1 名 + 10 个第 2 名),不是“最多取 2 行” - 语法和
RANK()完全一致,仅函数名不同:DENSE_RANK() OVER (ORDER BY revenue DESC)
什么时候必须用 RANK(),什么时候该换 DENSE_RANK()
选错函数会导致过滤逻辑彻底失效,不是风格问题,是语义错位。
用 RANK() 的典型场景:
- 奥运奖牌榜式排名:两个金牌后,银牌就是第三名,不是第二名 “跨越了多少个门槛值”类分析,比如“客户消费额超过前 5 档中哪几档”
用 DENSE_RANK() 的典型场景:
- 分 ABC 三档:A 档(1)、B 档(2)、C 档(3),不能缺档也不能多档
- “每科成绩的班级内排名”,且要求名次序列连续可读
- 后续要接
NTILE(10)或做等宽分位,需要紧凑整数序列
实际过滤时最容易踩的坑
两个函数都**不能**在 WHERE 或 HAVING 中直接使用别名,比如下面会报错:
SELECT product, revenue, RANK() OVER (ORDER BY revenue DESC) AS rnk FROM sales WHERE rnk <= 3;
正确做法只有两种:
- 子查询嵌套:
SELECT * FROM (SELECT ..., RANK() OVER (...) AS rnk FROM sales) t WHERE rnk - CTE:
WITH ranked AS (SELECT ..., RANK() OVER (...) AS rnk FROM sales) SELECT * FROM ranked WHERE rnk
注意:PARTITION BY 忘写或写错字段,会让整个排名失去业务意义——比如想算“每个部门内薪资排名”,却漏了 PARTITION BY dept,结果变成全校统排。

















