rank()返回1,1,3,4而非1,1,2,3,因其按“唯一值段”分配名次:100占第1段(2行),下一段起始名次为1+2=3;dense_rank()则按“第几个不同值”编号,100、95、90依次为1、2、3,保证档位连续无空缺。

RANK() 跳号,DENSE_RANK() 不跳号——这不是实现问题,而是语义差异:前者按“不同值个数 + 1”算名次,后者按“当前是第几个不同值”算档位。
为什么 RANK() 返回 1, 1, 3, 4 而不是 1, 1, 2, 3
RANK() 的逻辑是:比当前值大的**不同值的个数** + 1。分数 [100, 100, 95, 90] 降序排列时:
- 前两行值为 100 → 比它大的不同值个数为 0 → 排名 = 0 + 1 = 1
- 第三行值为 95 → 比它大的不同值只有
{100}→ 个数为 1 → 排名 = 1 + 1 = 2?不对,实际是 3 - 真正规则是:每个唯一值独占一段名次,段与段之间不留空位编号,但段内并列者共享该段起始名次;下一段名次 = 当前段名次 + 当前段行数
- 所以 100 占段 1(长度 2),95 就从名次 3 开始
常见错误现象:RANK() 结果里“缺了第 2 名”,其实是 95 分属于第二段,而这一段被命名为 3 —— 它反映的是“断层感”,不是漏算。
为什么 DENSE_RANK() 更适合分档场景
DENSE_RANK() 只关心“这是第几个不同的排序值”,不计并列行数:
- 值 100 → 第 1 个不同值 →
dense_rank = 1 - 值 95 → 第 2 个不同值 →
dense_rank = 2 - 值 90 → 第 3 个不同值 →
dense_rank = 3
使用场景明确:
- 做销售额 A/B/C 三档划分,必须严格对应
dense_rank IN (1, 2, 3),不能接受空档或超档 - 但要注意:
WHERE dense_rank 可能返回 20 行(比如 18 人并列第 2 名),不是“前 2 名”,而是“前 2 档” - 它不会合并行,只是编号连续;每行仍独立存在,
dense_rank值相同仅表示档位一致
WHERE 中直接用 RANK() 或 DENSE_RANK() 会报错
窗口函数在 SELECT 阶段才计算,而 WHERE 执行在之前。以下写法必然失败:
SELECT * FROM scores WHERE RANK() OVER (ORDER BY score DESC) <p>报错信息通常是 <code>Invalid use of window function</code> 或字段不存在。正确做法必须嵌套:</p><pre class="brush:php;toolbar:false;">SELECT * FROM ( SELECT *, RANK() OVER (ORDER BY score DESC) AS rnk FROM scores ) t WHERE rnk
- 漏掉这层子查询或 CTE 是新手最高频错误
- 如果还用了
PARTITION BY dept,却只写OVER (ORDER BY score DESC),结果就是全表统一排名,业务逻辑全错 -
PARTITION BY字段必须出现在外层SELECT列表中,否则下游无法对齐分组
真正容易被忽略的点是:跳不跳号本身不决定对错,只反映你到底想表达“段位断层”还是“档位连续”——选错函数,不是语法问题,是业务语义跑偏了。











