DENSE_RANK()更符合多数业务排名逻辑,因其并列不跳号,名次连续(如1,1,2,3),直接对应“第几档”业务语义;RANK()并列后跳号(如1,1,3,4),查Top N可能漏数据。
DENSE_RANK() 更符合多数业务排名逻辑,是因为它不跳号 —— 排名数字连续、可预期,直接对应“第几档”或“第几级”的业务语义。
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 稳定覆盖全部三档,无歧义
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,导致跨部门比较时档位数量失真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 已执行完毕。
DENSE_RANK() 不可用PARTITION BY 却漏写,比如本该按 region 分组,却只写 ORDER BY sales,结果就变成全表统一排名,业务逻辑全歪真正容易被忽略的点是:跳不跳号本身不改变函数性能,也不影响语法,但它直接决定你写的 WHERE dense_rank <= N 是不是真能代表“前 N 档”——而业务要的往往不是“名次”,是“档位”。