应优先使用dense_rank()而非rank(),因其生成连续档位编号,避免跳号导致漏人、下游系统报错及excel复核不一致;同时必须配合正确的partition by确保分组口径与业务一致。

DENSE_RANK() 直接生成连续档位编号,而 RANK() 的跳号逻辑会让“二等奖”在数据里根本不存在——这不是bug,是设计,但业务上无法接受。
查“前N档”时,RANK() 会漏人
比如按销售额分档,要求取“前三档”产品:WHERE rank 看似合理,但若 <code>RANK() 返回的是 1, 1, 3, 4, 4, 6,那第3档(值为3)只覆盖一个产品,而实际并列第2高销售额的那批产品(本该是第2档)因没拿到数字2,被整个过滤掉了。DENSE_RANK() 返回 1, 1, 2, 3, 3, 4,WHERE dense_rank 才真正命中前三档全部成员。
下游系统默认名次 = 档位序号
教务系统、HR绩效模块或BI看板常把排名字段直接映射为“档位标签”,例如:1 → A档、2 → B档、3 → C档。一旦 RANK() 给出 1, 1, 3,下游就会:
• 把第3个学生标成 C 档,却找不到 B 档对应记录
• 校验逻辑报错:“档位序列不连续,缺失 B 档定义”
• 运维被迫人工补档或写额外 CASE 语句兜底
和 Excel / 业务习惯对不上
业务方导出数据后常在 Excel 里用 RANK.EQ() 复核,而它的行为就是密集排名(等价于 DENSE_RANK())。如果 SQL 用 RANK(),两边结果必然不一致,每次都要解释“为什么Excel是1,1,2,数据库是1,1,3”——这种沟通成本远高于改一个函数名。另外,PARTITION BY department ORDER BY score DESC 这种按部门独立分档的需求,DENSE_RANK() 依然保持档位连续,而 RANK() 在每个分区里都可能制造空档。
真正容易被忽略的是:排名函数本身不决定档位含义,PARTITION BY 的粒度才决定谁跟谁比。哪怕用了 DENSE_RANK(),如果忘了加 PARTITION BY class_id,全校统排出来的“第1档”对班级老师就没意义。函数选对只是第一步,分组边界必须跟业务口径严格对齐。











