RANK() 适合“并列后跳号”,DENSE_RANK() 才实现“并列不跳号、档位连续”;RANK() 在并列时跳过后续名次,导致查 Top N 漏数据、分档缺档。

直接说结论:RANK() 适合需要“并列后跳号”的场景(比如两个第一,第三名就是季军);DENSE_RANK() 才是真正解决“并列不跳号、档位连续”问题的函数——查 Top N 容易漏数据、分档时缺档,90% 都是因为错用了 RANK()。
查 Top N 为什么 RANK() 会漏行
因为 RANK() 在并列后直接跳过后续名次。例如销售额为 [100, 95, 95, 90],RANK() OVER (ORDER BY sales DESC) 返回的是 [1, 2, 2, 4],根本没有名次 3。所以 WHERE rk 只能命中前 3 行(名次 1 和两个 2),但第 3 高值(90)被跳过了。
- 想取“销售额前 3 名”,且必须包含所有并列者 → 用
DENSE_RANK() - 想取“严格最多 3 条记录”,不管并列 → 用
ROW_NUMBER() -
RANK()的 WHERE 过滤要格外小心:它返回的名次集合可能不连续,rk = 3可能根本不存在
DENSE_RANK() 怎么保证分档不缺档
业务要求“按销售额分 A/B/C 三档”,对应名次 1/2/3 ——这时只有 DENSE_RANK() 能稳住档位编号。它按“当前有多少个更优的**不同值**”计数,相同值复用名次,后续紧接,不会出现 1、2、4 这种断层。
- 错误写法:
RANK() OVER (ORDER BY sales DESC) AS rk→ 若销售值为[100, 95, 95, 80],结果是[1, 2, 2, 4],rk = 3缺失,B 档(名次=2)查得到,C 档(名次=3)查不到任何数据 - 正确写法:
DENSE_RANK() OVER (ORDER BY sales DESC) AS drk→ 同样数据返回[1, 2, 2, 3],C 档始终有数据 - 注意:
DENSE_RANK()不合并行,只是打标签;输出仍是原始行数,不是聚合结果
OVER 子句里 ORDER BY 写错就全翻车
并列判定只看 ORDER BY 中最左字段是否相等,后面字段仅用于破 ties(稳定排序顺序)。把破 ties 字段混进主排序逻辑,会让本该并列的行被强行拆开。
- 错误:
RANK() OVER (ORDER BY sales DESC, emp_id ASC)→ 即使sales相同,只要emp_id不同,名次就不同 - 正确:
RANK() OVER (ORDER BY sales DESC) AS rk,再在最终ORDER BY加sales DESC, emp_id ASC控制展示顺序 - NULL 值默认行为因版本而异:SQL Server 默认
NULLS FIRST(升序)或NULLS LAST(降序)不统一,建议显式处理,如ORDER BY COALESCE(sales, 0) DESC
WHERE 里不能直接引用排名别名
窗口函数在逻辑查询处理阶段晚于 WHERE,所以 WHERE rk 一定报错。必须用子查询或 CTE 包一层。
- 错误:
SELECT *, RANK() OVER (ORDER BY sales DESC) AS rk FROM t WHERE rk - 正确(子查询):
SELECT * FROM (SELECT *, RANK() OVER (ORDER BY sales DESC) AS rk FROM t) t2 WHERE t2.rk - 正确(CTE):
WITH ranked AS (SELECT *, DENSE_RANK() OVER (ORDER BY sales DESC) AS drk FROM t) SELECT * FROM ranked WHERE drk - 如果只想要 Top N 行(非 Top N 名次),加
TOP N或OFFSET ... FETCH更高效,避免全表计算排名
真正卡住人的,往往不是函数不会用,而是没意识到:排名函数返回的是中间计算列,不能参与 WHERE;ORDER BY 的字段组合决定了并列边界;而 RANK() 和 DENSE_RANK() 的区别,本质是“要不要让下游系统面对空档”。

















