178. 分数排名

SQL 排名问题:根据分数进行排名并处理相同分数的情况

在数据库开发和数据分析中,经常遇到根据某些标准对数据进行排序并生成排名的问题。特别是,在处理比赛成绩、销售业绩、考试成绩等应用场景时,计算排名是不可避免的任务。本篇博客将深入探讨一个常见的 SQL 排名问题:如何根据分数进行排名,并确保在有相同分数时能够正确处理排名。

题目描述

假设我们有一张名为 Scores 的表,记录了每场比赛的分数。表的结构如下:

Column Name

Type

id

int

score

decimal

  • id 是该表的主键,每一行代表一场比赛的分数。
  • score 是比赛的分数,具有两位小数。

任务是根据以下规则计算每个比赛的排名:

  1. 分数应该按从高到低排序。
  2. 如果两个分数相等,那么两个分数的排名应该相同。
  3. 在排名相同的分数后,排名数应该是下一个连续的整数。
<think>好的,我现在需要帮助用户解决LeetCode 178分数排名MySQL解法二的具体实现和逻辑。首先,我需要回顾一下用户提供的引用内容,尤其是引用[3]中提到的MySQL变量用法。用户之前询问过如何在BEGIN块中重命名变量和对象,现在转向分数排名的具体问题,这可能需要使用变量来处理排名逻辑。 首先,我需要确认LeetCode 178题的要求。根据引用[3],题目要求为分数排名,如果分数相同则排名相同,且后续的排名不应有空缺,比如并列第一后下一个是第二,而不是第三。这类似于DENSE_RANK()函数的功能,但MySQL 5.7可能不支持窗口函数,所以需要使用变量模拟。 用户提到的解法二可能指的是使用用户变量来手动计算排名。我需要回忆常见的解决方案,通常有两种方法:一种使用子查询计算每个分数排名,另一种使用变量来跟踪当前分数和前一个分数,从而生成排名。解法二可能就是基于变量的方法。 接下来,我需要考虑如何正确初始化变量,并确保在排序后的分数序列中正确递增排名。同时要注意处理相同分数的情况,即当当前分数等于前一个分数时,排名不变,否则排名递增。 需要确保变量的作用域和赋值顺序正确。在MySQL中,用户变量的赋值依赖于查询的执行顺序,因此在排序后的结果集上处理变量是关键。可能需要将数据按分数降序排列,然后逐行比较当前分数与前一个分数,以确定是否增加排名。 另外,用户可能对变量的初始化和更新过程有疑问,比如是否需要使用SET语句或在SELECT中直接赋值。根据引用[3]中的例子,可能在SELECT语句中直接进行变量赋值,这需要正确使用:=操作符,并注意语句的执行顺序。 还需要注意结果是否正确处理了并列的情况,并且排名没有空缺。例如,分数90,90,80应该得到排名1,1,2。这需要确保当分数变化时,排名递增,但相同分数保持相同排名。 最后,需要验证这个解法在MySQL环境中的可行性,尤其是在不同版本中的表现,比如是否在MySQL 5.7中有效,因为某些版本可能对变量的使用有更严格的限制。同时,要确保没有语法错误,比如变量赋值的位置是否正确,是否需要使用子查询或临时表来稳定排序。 总结来说,解法二的核心逻辑是使用用户变量跟踪前一个分数和当前排名,通过比较当前分数与前一个分数来决定是否更新排名。这需要在SELECT语句中正确排序数据,并按顺序处理每一行来生成正确的排名。</think>#### LeetCode 178 分数排名解法二:变量法实现详解 通过**用户变量自定义排序规则**,实现MySQL 5.x版本的DENSE_RANK效果。此方法核心逻辑为:**比较当前行与上一行分数,动态生成无间隔的连续排名**。 --- ### **一、完整实现代码** ```sql SELECT score, @rank := IF( @prev_score = score, @rank, IF(@prev_score := score, @rank + 1, @rank + 1) ) AS 'rank' FROM Scores, (SELECT @rank := 0, @prev_score := NULL) AS init ORDER BY score DESC; ``` --- ### **二、核心逻辑拆解** 1. **变量初始化** ```sql (SELECT @rank := 0, @prev_score := NULL) AS init ``` - `@rank`:存储当前排名值,初始为0 - `@prev_score`:记录前一行分数,初始为NULL[^3] 2. **排序控制** ```sql ORDER BY score DESC -- 强制按分数降序处理数据流 ``` 3. **动态计算逻辑** ```sql @rank := IF( @prev_score = score, -- 条件判断:当前行是否与前一行同分 @rank, -- 同分则保持当前排名 IF(@prev_score := score, -- 不同分时: @rank + 1, -- 更新排名值 @rank + 1) -- 保证表达式语法正确 ) ``` - **同分处理**:`@prev_score = score`成立时,直接返回当前`@rank` - **不同分处理**:更新`@prev_score`为当前分数,并执行`@rank = @rank + 1` --- ### **三、执行流程示例** 以输入数据`[100, 100, 90, 80]`为例: | 处理顺序 | score | @prev_score | @rank | 计算逻辑 | |----------|-------|-------------|-------|-----------------------------| | 初始状态 | - | NULL | 0 | 初始化变量 | | 第1行 | 100 | →100 | 0+1=1 | 不同分,更新prev_score和rank | | 第2行 | 100 | 100 | 1 | 同分,保持rank | | 第3行 | 90 | →90 | 1+1=2 | 不同分,更新prev_score和rank | | 第4行 | 80 | →80 | 2+1=3 | 不同分,更新prev_score和rank | 输出结果: ``` +-------+------+ | score | rank | +-------+------+ | 100 | 1 | | 100 | 1 | | 90 | 2 | | 80 | 3 | +-------+------+ ``` --- ### **四、技术要点解析** 1. **变量赋值顺序** MySQL按`ORDER BY`排序后的顺序逐行处理数据流,确保比较逻辑的正确性[^3] 2. **表达式执行机制** - `IF(@prev_score := score, ...)`中,先执行赋值操作再返回判断结果 - 赋值表达式返回值是赋予的值,非布尔类型值 3. **临时表必要性** 通过`(SELECT ...) AS init`创建临时表,确保每行处理前完成变量初始化 --- ### **五、与窗口函数对比** | 维度 | 变量法 | DENSE_RANK() | |--------------|---------------------------|----------------------------| | 兼容性 | MySQL 5.x | MySQL 8.0+ | | 执行效率 | 单次扫描表(O(n)) | 依赖优化器实现 | | 可维护性 | 需要手动处理变量状态 | 声明式语法更直观 | | 并列处理 | 完美支持 | 原生支持 | --- ### **六、常见问题排查** 1. **排名全部为1** - 检查`ORDER BY`是否正确使用`DESC`排序 - 确认变量初始化位置在FROM子句中 2. **出现间隔跳跃** - 验证`@rank`递增逻辑是否错误写成`@rank := @rank + 2` - 检查是否误用`RANK()`的跳跃逻辑 3. **NULL值处理异常** - 添加`WHERE score IS NOT NULL`过滤条件 - 使用`COALESCE(score, 0)`处理空值 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值