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

DENSE_RANK 排名(并列不跳号)

并列名次相同且后续不跳号(1,1,2,3…):适合“等级档位”类排名展示。

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

并列不跳号的排名

同一组数据按分值排名时,并列怎么算有三种口径:并列名次相同且后续不跳号、并列名次相同但后续跳号、以及完全不允许并列。三种结果的差别只在并列处体现,但展示效果与业务含义完全不同——榜单上「并列第三名之后是第四名」还是「直接跳到第五名」,是产品需要明确的问题,不是开发随手选一个函数的事。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
不跳号排名并列同名次,后续编号连续
跳号排名并列同名次,后续按占用位次跳号
行号严格按顺序编号,不产生并列
分区能力三者都支持按分区分别排名

典型使用场景

  • 考试或考核结果:同分并列,后续名次如何展示
  • 销售榜单:同额并列时的名次展示规则
  • 会员等级分档:按累计消费额确定档位,并列归入同一档
  • 分组内排名:每个部门内部单独排名
  • 对比三种排名函数在同一次查询里的差异

三种排名并列写在一起

三种排名并列写在一起
-- 三种排名同时输出,便于核对并列处差异
SELECT name, score,
       ROW_NUMBER() OVER (ORDER BY score DESC) AS rn,   -- 严格编号,不并列
       RANK()       OVER (ORDER BY score DESC) AS rk,   -- 并列同名次,后续跳号
       DENSE_RANK() OVER (ORDER BY score DESC) AS drnk  -- 并列同名次,后续不跳号
FROM exams
ORDER BY score DESC, name;

-- 分组内排名:每个班级内部各自排名
SELECT class_id, name, score,
       DENSE_RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS drnk
FROM exams
ORDER BY class_id, drnk;

-- 取每组前若干名:先排名再筛行号
SELECT * FROM (
  SELECT class_id, name, score,
         ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS rn
  FROM exams
) t WHERE rn <= 3;

并列处的结果差异

分值序列行号排名跳号排名不跳号排名
100111
95222
95322
90443
85554
分值与排序规则要一起看:如果分值列是字符串,排序会按字典序而不是数值大小,出现「100 排在 99 前面」的情况,名次自然也是错的。
取「每组前几名」时要用行号而不是不跳号排名:不跳号排名在并列时会一次取出多于预期的行数,例如并列第二的两行都会入选。

易错点

  • 业务要求「第几名」却不确认并列口径,三种函数结果不同,上线后名次展示与预期不符
  • 分值列用字符串存储,字典序排序让名次完全错乱,应先转换类型
  • 取前几名时用了并列排名,并列处一次取出超出行数限制的记录
  • 排名没有稳定的次级排序键,同分行之间的先后顺序在多次执行间变化
  • 在超大表上对全表排名后又只取少量行,排序代价与结果集规模成正比

数据来源与参考

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