首页/数据/SQL 速查/RANK 排名(并列跳号)
聚合与窗口函数54 条

RANK 排名(并列跳号)

按排序值排名:并列名次相同,后续名次跳号(1,1,3…);取“前 N 名含并列”用 RANK 而不是 ROW_NUMBER。

SQL 速查数据更新于 2026-10-13

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永不并列,同值行也按顺序编号
取前 NRANK() <= 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。

易错点

  • 用 ROW_NUMBER 取前 N 名:并列的记录会被截掉一部分,评奖评优类需求应改用 RANK
  • 漏写 PARTITION BY:本想按部门排名,结果变成全公司排名,名次全部错位
  • 排序键不唯一:同值行名次相同但相对次序不确定,需要补次级排序键
  • 把名次当唯一标识:并列会导致名次重复,不能用作主键或关联键

数据来源与参考

  • MySQL 8.0 Reference Manual · RANK
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌