一、连续并列排名
需求:相同值记录共享同一排名,总排名连续(如 1,1,3)
1. 自连接实现
SELECT s1.id, s1.score,
(SELECT COUNT(DISTINCT s2.score)
FROM scores s2
WHERE s2.score >= s1.score) AS rank
FROM scores s1
ORDER BY s1.score DESC;
解释:
- 使用
COUNT(DISTINCT s2.score)去重相同分数 - 结果示例:1,1,3
2. 变量实现
SELECT s.score,
IF(@pre_score = s.score, @cur_rank, @cur_rank := @cur_rank + 1) ranking,
@pre_score := s.score
FROM score s, (SELECT @cur_rank :=0, @pre_score := NULL) r
ORDER BY s.score DESC;
解释:
- 变量
@pre_score记录上一条分数 @cur_rank在分数变化时递增
二、连续不并列排名
需求:每条记录唯一排名,连续递增(如 1,2,3)
1. 自连接实现
SELECT s1.id, s1.score,
(SELECT COUNT(*)
FROM scores s2
WHERE s2.score >= s1.score) AS rank
FROM scores s1
ORDER BY s1.score DESC;
解释:
- 使用
COUNT(*)计算所有更高或相等分数 - 结果示例:1,2,3
2. 变量实现
SELECT s.score, (@cur_rank := @cur_rank + 1) ranking
FROM score s, (SELECT @cur_rank := 0) r
ORDER BY score DESC;
解释:
- 每次查询直接递增计数器
@cur_rank
三、不连续并列排名
需求:相同值共享排名,后续排名跳过并列数(如 1,1,3)
1. 自连接实现
SELECT s1.id, s1.score,
(SELECT COUNT(*)
FROM (SELECT DISTINCT score FROM scores) s2
WHERE s2.score > s1.score) + 1 AS rank
FROM scores s1
ORDER BY s1.score DESC;
解释:
- 子查询先提取唯一分数
- 计算严格更高的唯一分数数量
2. 变量实现
SELECT s.score,
@rank_counter := @rank_counter + 1,
IF(@pre_score = s.score, @cur_rank, @cur_rank := @rank_counter) ranking,
@pre_score := s.score
FROM score s, (SELECT @cur_rank :=0, @pre_score := NULL, @rank_counter := 0) r
ORDER BY s.score DESC;
解释:
@rank_counter全局递增@cur_rank仅在分数变化时更新
四、分组连续不并列排名
需求:分组内唯一连续排名(如组 1:1,2,3;组 2:1,2)
1. 自连接实现
SELECT s1.group_id, s1.id, s1.score,
(SELECT COUNT(*)
FROM scores s2
WHERE s2.group_id = s1.group_id
AND s2.score >= s1.score) AS rank
FROM scores s1
ORDER BY s1.group_id, s1.score DESC;
解释:
- 增加
group_id条件限定分组范围
2. 变量实现
SELECT s.course_id, s.score,
IF(@pre_course_id = s.course_id, @cur_rank := @cur_rank + 1, @cur_rank := 1) ranking,
@pre_course_id := s.course_id
FROM score s, (SELECT @cur_rank := 0, @pre_course_id := NULL) r
ORDER BY course_id, score DESC;
解释:
- 检测分组切换时重置计数器
五、分组连续并列排名
需求:分组内相同值共享排名,总排名连续(如组 1:1,1,3;组 2:1,2)
1. 自连接实现
SELECT s1.group_id, s1.id, s1.score,
(SELECT COUNT(DISTINCT s2.score)
FROM scores s2
WHERE s2.group_id = s1.group_id
AND s2.score >= s1.score) AS rank
FROM scores s1
ORDER BY s1.group_id, s1.score DESC;
解释:
- 分组内去重分数计算排名
2. 变量实现
SELECT s.course_id, s.score,
IF(@pre_course_id = s.course_id,
IF(@pre_score = s.score, @cur_rank, @cur_rank := @cur_rank + 1),
@cur_rank := 1) ranking,
@pre_score := s.score,
@pre_course_id := s.course_id
FROM score s, (SELECT @cur_rank :=0, @pre_score := NULL, @pre_course_id := NULL) r
ORDER BY course_id, score DESC;
解释:
- 双重条件判断分组和分数变化
六、分组不连续并列排名
需求:分组内相同值共享排名,后续排名跳过并列数(如组 1:1,1,3;组 2:1,2)
1. 自连接实现
SELECT s1.group_id, s1.id, s1.score,
(SELECT COUNT(*)
FROM (SELECT DISTINCT score FROM scores WHERE group_id = s1.group_id) s2
WHERE s2.score > s1.score) + 1 AS rank
FROM scores s1
ORDER BY s1.group_id, s1.score DESC;
解释:
- 分组内先提取唯一分数
2. 变量实现
SELECT s.course_id, s.score,
IF(@pre_course_id = s.course_id,
@rank_counter := @rank_counter + 1,
@rank_counter := 1) temp1,
IF(@pre_course_id = s.course_id,
IF(@pre_score = s.score, @cur_rank, @cur_rank := @rank_counter),
@cur_rank := 1) ranking,
@pre_score := s.score,
@pre_course_id := s.course_id
FROM score s, (SELECT @cur_rank := 0, @pre_course_id := NULL,
@pre_score := NULL, @rank_counter := 1) r
ORDER BY s.course_id, s.score DESC;
解释:
- 引入
@rank_counter跟踪全局位置
总结对比
| 排名类型 | 自连接核心逻辑 | 变量核心逻辑 | 结果特征 |
|---|---|---|---|
| 连续并列 | COUNT(DISTINCT) 去重 | 比较上一条分数 | 允许重复,连续递增 |
| 连续不并列 | COUNT(*) 全量计数 | 直接递增计数器 | 无重复,连续递增 |
| 不连续并列 | 唯一分数排序计数 | 双重变量跟踪 | 允许重复,跳过并列数 |
| 分组排名 | 添加 group_id 条件 | 检测分组切换重置变量 | 分组内独立计算 |