dense_rank()专为“并列不跳号”设计,天然满足并列同名次、后续紧接、无空档,比rank()更贴近业务真实逻辑;直接where dense_rank可准确筛选前n档,避免rank()因跳号导致漏档。

DENSE_RANK() 就是专为“并列不跳号”设计的,不是技巧,是语义本身。它天然满足并列同名次、后续紧接、无空档这三点,比 RANK() 更贴近多数业务场景的真实排名逻辑。
为什么直接 WHERE dense_rank
窗口函数计算发生在 WHERE 过滤之后,SQL Server 不允许在 WHERE 中引用 DENSE_RANK() 的别名。你写的 WHERE drk 会提示 “无效列名” 或 “列不在 FROM 子句中”。
- 必须用子查询或 CTE 包一层:先算出
DENSE_RANK(),再在外层过滤 - 不能写成
SELECT *, DENSE_RANK() OVER (...) AS drk FROM t WHERE drk - 正确写法示例:
SELECT * FROM (SELECT *, DENSE_RANK() OVER (ORDER BY score DESC) AS drk FROM students) t WHERE drk
分组内排名漏写 PARTITION BY 就全表混排
比如按部门查“各科室绩效前3”,如果忘了 PARTITION BY dept_id,所有员工会被拉到一起排名,结果完全失真。
- 错误写法:
DENSE_RANK() OVER (ORDER BY score DESC)→ 全公司统一排 - 正确写法:
DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY score DESC) - 注意
dept_id为 NULL 的行会被归入同一个隐式分区,建议加WHERE dept_id IS NOT NULL
排序字段含 NULL 时排名意外靠前
SQL Server 默认把 NULL 排在最前面(ASC)或最后面(DESC),但实际业务中常希望空值排末尾——比如未提交绩效的员工不该占第1名。
- SQL Server 不支持
NULLS LAST,得用COALESCE(score, -1)或CASE WHEN score IS NULL THEN -1 ELSE score END - 推荐写法:
DENSE_RANK() OVER (ORDER BY COALESCE(score, -1) DESC) - 避免用
ISNULL(score, 0)—— 若真实分数有负数,0 可能干扰排序
真正容易被忽略的是:DENSE_RANK() 的“连续”只在每组内部成立,跨组不累计;而一旦和 GROUP BY 混用,窗口函数就失效了——因为聚合后原始行已不存在。











