排行榜应优先使用DENSE_RANK()实现并列不跳位,如95分两人并列第1、90分排第2;RANK()用于并列跳位(如奥运奖牌榜,95分并列第1后直接第3);分组排名需加PARTITION BY,如按班级独立排序。

SQL 实现排行榜并正确处理并列名次,关键在于选择合适的窗口函数:用 RANK() 处理“并列跳位”,用 DENSE_RANK() 处理“并列不跳位”,用 ROW_NUMBER() 则完全不并列。实际业务中,大多数排行榜(如积分榜、销量榜)倾向使用 DENSE_RANK(),因为它更符合用户对“第几名”的直观理解。
用 DENSE_RANK() 实现并列不跳位的排行榜
当多名用户分数相同时,他们应共享同一排名,后续名次紧接其后(例如:95分两人并列第1,90分就排第2,而非第3)。这是最常用的并列逻辑。
- 语法简洁:DENSE_RANK() OVER (ORDER BY score DESC)
- 按 score 降序排列,相同 score 得到相同 rank,且无空缺
- 示例:数据为 (A,95), (B,95), (C,90), (D,85) → 排名结果为 1,1,2,3
用 RANK() 实现并列跳位(传统体育式排名)
适合强调“名次段落”的场景,比如奥运奖牌榜:两个第1名后,下一个有效名次是第3名(跳过第2名)。
- 语法类似:RANK() OVER (ORDER BY score DESC)
- 相同 score 得相同 rank,但会跳过被占用的后续名次数值
- 同上示例 → 排名结果为 1,1,3,4
- 注意:若需限制只取前10名,RANK() 可能返回超过10行(因并列导致 rank=10 对应多条记录)
如何分组内独立排行(如各班级内部排名)
排行榜常需“分组计算”,比如每个班级单独排成绩名次。只需在窗口函数中加入 PARTITION BY。
- 写法:DENSE_RANK() OVER (PARTITION BY class_id ORDER BY score DESC)
- class_id 相同的数据被划为一组,每组内独立排序、独立编号
- 支持多级排序,例如先按班级,再按性别,再按分数:PARTITION BY class_id, gender ORDER BY score DESC
补充:兼容旧版本 MySQL(
MySQL 5.7 及更早不支持窗口函数,可用变量或自连接模拟 DENSE_RANK(),但性能差、逻辑易错,仅作临时过渡。
- 推荐升级至 MySQL 8.0+,直接使用标准窗口函数
- 若必须兼容,核心思路是:先去重排序得到唯一分数列表,再关联原表匹配名次
- 例如:SELECT t1.name, t1.score, COUNT(DISTINCT t2.score) + 1 AS rank FROM scores t1 LEFT JOIN scores t2 ON t2.score > t1.score GROUP BY t1.name, t1.score ORDER BY rank;










