RANK 是什么
RANK 按排序值给行排名:并列名次相同,后续名次跳号,形成 1、1、3、4。它与 DENSE_RANK(并列但不跳号)和 ROW_NUMBER(永不并列)分工不同:要“前 N 名且保留并列”用 RANK,要“每组固定一行”用 ROW_NUMBER。
基本信息
| 语法 | RANK() OVER ([PARTITION BY …] ORDER BY …) |
|---|---|
| 并列处理 | 排序值相同的行名次相同 |
| 跳号 | 并列占位,后续名次跳过,例如 1、1、3 |
| DENSE_RANK | 并列不跳号,例如 1、1、2 |
| ROW_NUMBER | 永不并列,同值行也按顺序编号 |
| 取前 N | RANK() <= N 会包含并列行,结果可能多于 N 条 |
三种排名对比
三种排名对比
SELECT name, score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS rn, -- 1,2,3:绝不并列
RANK() OVER (ORDER BY score DESC) AS rnk, -- 1,1,3:并列后跳号
DENSE_RANK() OVER (ORDER BY score DESC) AS drnk -- 1,1,2:并列不跳号
FROM exams
ORDER BY score DESC;
-- 想取冠亚季军且保留并列,用 WHERE rnk <= 3组内排名
组内排名
-- 每个班级内部排名:先按班级分区,再在班内排序
SELECT class_id, name, score,
RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS rnk_in_class
FROM exams
ORDER BY class_id, rnk_in_class;
-- 漏写 PARTITION BY 就变成全校统一排名,名次全错排名函数对比
| 函数 | 并列时表现 | 典型用途 |
|---|---|---|
| ROW_NUMBER | 不并列,按顺序编号 | 每组固定取一行、去重 |
| RANK | 并列同名次,后续跳号 | 取前 N 名,允许并列超额 |
| DENSE_RANK | 并列同名次,后续不跳号 | 档位分级,名次连续 |
| NTILE(n) | 按行数分桶 | 分层抽样、分位统计 |
典型使用场景
- 成绩、业绩排行榜,允许并列名次
- 部门内排名:加 PARTITION BY 按部门分组
- 取前 N 名:要并列用 RANK,要严格限行用 ROW_NUMBER
- 档位划分:把指标映射成 A、B、C 等级
- 分层抽样:配合 NTILE 把数据切成若干层
- 找异常记录:关注排名最前与最后的尾部数据
- 比赛计分:并列名次保留,后续名次按实际名次显示
- 排行榜分页:按名次排序后分页展示,注意并列项在同一页
名次由排序表达式决定,多列排序要写完整:ORDER BY score DESC, name ASC 能让同分记录按姓名有稳定顺序,否则同分行之间的相对次序并不确定。
名次是计算出来的结果列,不落库:如果要保存名次,需要在写入时重算整表名次,或者干脆在查询时现算。提前落库的名次在数据变更后会立刻过期。
取“前 3 名”时 RANK 与 ROW_NUMBER 结果可能不同:RANK 会把并列第一的两行都算进来,最终可能返回 2 行或 4 行。业务要求严格返回 3 条时必须用 ROW_NUMBER。