一聚教程网:一个值得你收藏的教程网站

热门教程

为何在SQL中使用DENSE_RANK()比RANK()更符合业务排名逻辑?

时间:2026-07-03 10:56:51 编辑:袖梨 来源:一聚教程网

DENSE_RANK()更符合多数业务排名逻辑,因其并列不跳号,名次连续(如1,1,2,3),直接对应“第几档”业务语义;RANK()并列后跳号(如1,1,3,4),查Top N可能漏数据。

DENSE_RANK() 更符合多数业务排名逻辑,是因为它不跳号 —— 排名数字连续、可预期,直接对应“第几档”或“第几级”的业务语义。

查“Top 3”时,RANK() 可能漏数据

比如销售额为 [100, 100, 90, 85, 80]RANK() 结果是 [1, 1, 3, 4, 5]。用 WHERE rank 只能拿到前三行(两个 100 和一个 90),看似没问题;但若数据变成 <code>[100, 100, 95, 95, 80]RANK() 就是 [1, 1, 3, 3, 5]rank 会返回前四行(两个 100 + 两个 95),而 <code>rank = 3 实际代表“第三档”,不是“第三名”。业务上想取“前三档”,RANK()3 却跳过了 2,语义断裂。

  • DENSE_RANK() 在同样数据下给出 [1, 1, 2, 2, 3]dense_rank 稳定覆盖全部三档,无歧义
  • 报表里写“A档(第1名)、B档(第2名)、C档(第3名)”,DENSE_RANK() 的输出天然匹配这个映射
  • RANK()1,1,3 容易让业务方追问:“第2名去哪了?”——这不是数据错,是函数语义和业务理解错位

DENSE_RANK()PARTITION BY 行为更可控

按部门分组排名时,DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) 每个部门都从 1 开始、连续编号。哪怕某部门只有两人并列第一,另一部门有五人分四档,各组的档位数仍保持可比性(都是 1→2→3…)。

  • RANK() 在小分组里可能只出现 1,1,4,导致跨部门比较时档位数量失真
  • 做绩效分级(S/A/B/C)时,必须保证每档都有编号,且不能缺档——DENSE_RANK() 天然支持,RANK() 需额外补档逻辑
  • 如果排序字段存在重复且未加唯一键兜底(如只按 score 排),DENSE_RANK() 结果仍稳定;但 ROW_NUMBER() 可能每次执行顺序不同,RANK() 虽稳定,档位断层问题照旧

别在 WHERE 里直接用窗口函数

无论选 RANK() 还是 DENSE_RANK(),都不能写成:

SELECT * FROM sales WHERE DENSE_RANK() OVER (ORDER BY amount DESC) <= 3;

这会报错:Invalid use of window function 或字段不存在。窗口函数在 SELECT 阶段才计算,WHERE 已执行完毕。

  • 正确写法必须套一层子查询或 CTE
  • 漏掉嵌套是新手最常踩的坑,和选哪个函数无关,但一旦出错,容易误以为是 DENSE_RANK() 不可用
  • 如果还用了 PARTITION BY 却漏写,比如本该按 region 分组,却只写 ORDER BY sales,结果就变成全表统一排名,业务逻辑全歪

真正容易被忽略的点是:跳不跳号本身不改变函数性能,也不影响语法,但它直接决定你写的 WHERE dense_rank <= N 是不是真能代表“前 N 档”——而业务要的往往不是“名次”,是“档位”。

热门栏目