DENSE_RANK() 跳号是因写法错误而非函数缺陷:漏写 PARTITION BY、在 WHERE 中引用排名别名、或未正确使用 OVER(ORDER BY ...) 导致逻辑错乱。

要用 DENSE_RANK() 正确处理并列排名,关键不是“怎么写函数”,而是“别让并列被误判成断层”——它天然不跳号,但写错位置、漏掉分区或混用逻辑,结果就全乱了。
为什么 DENSE_RANK() 一用就跳号?
跳号不是函数出错,是写法踩坑。最常见的是漏写 PARTITION BY 或在 WHERE 里直接引用排名别名。
-
DENSE_RANK()必须搭配OVER(),且ORDER BY是强制项;只写OVER(ORDER BY score DESC)就是全局排名,不是按部门/班级等分组排名 - 在
WHERE中直接写rank_in_dept 会报错:ERROR 1054(Unknown column),因为窗口函数在 WHERE 之后执行 - 如果排序字段含
NULL,PostgreSQL 默认NULLS FIRST,可能把空值排第一,造成并列出现在意料之外的位置
如何正确实现“并列即同号、后续紧连”?
核心是让 DENSE_RANK() 直接作用于原始明细行,不提前聚合、不去重、不套 ROW_NUMBER()。
- 多字段排序保稳定:用
ORDER BY score DESC, id,其中id是唯一列,仅用于破 ties,不影响并列逻辑 - 显式控制
NULL:写成ORDER BY CASE WHEN score IS NULL THEN 0 ELSE 1 END DESC, score DESC(兼容 MySQL/SQL Server)或ORDER BY score DESC NULLS LAST(PostgreSQL/Oracle) - 分区必须显式声明:比如按部门排名,
PARTITION BY dept_id不可省;若dept_id有NULL,建议先WHERE dept_id IS NOT NULL过滤
和 RANK() 混用时最危险的三个点
三者语法几乎一样,但行为差异会直接导致业务过滤失效,不是风格问题,是语义错位。
- 用
RANK()写WHERE rnk 查“前3名”,实际可能只返回2行(两人并列第1,第三人排第3);换成 <code>DENSE_RANK()后同样条件可能返回5行(1,1,2,2,3)——这不是 bug,是它按“新值个数”计数的必然结果 -
ROW_NUMBER()强制每行唯一编号,哪怕两行score完全相同也会编出 1、2;想保全所有并列者,它不能替代DENSE_RANK() - 在子查询里先用
ROW_NUMBER()去重再套DENSE_RANK(),等于提前破坏并列基础——窗口函数作用对象已不是原始明细行
Top N 查询中如何避免漏数据?
用 DENSE_RANK() 做 Top N 且允许并列时,必须接受“返回行数不固定”这个事实。
- 查“每个部门业绩前2档”,应写
DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY revenue DESC) ,而不是硬限 <code>LIMIT 2 - 若下游系统要求严格限制返回条数(如 BI 表格只显示10行),需在应用层截断,不能靠窗口函数压缩结果集
- 大数据量下慎用子查询嵌套模拟不跳号逻辑(如
SELECT MIN(rn) FROM (...) WHERE score >= outer.score),性能下降明显
真正容易被忽略的,是 DENSE_RANK() 的“稠密”只体现在名次序列上,不改变行数——10人并列第2名,它就真返回10行,不是帮你合并或筛选。业务逻辑是否能消化这种膨胀,得提前对齐,而不是等上线后发现报表卡死或导出 Excel 行数爆炸。

















