1 获取行号
编写一个 SQL 查询来实现分数排名。如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
例如,根据上述给定的 Scores 表,你的查询应该返回(按分数从高到低排列):
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rank-scores
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
select Score,cast(@rownum :=@rownum + (@pre <> (@pre :=Score)) as signed) as Rank
from Scores,(select @rownum :=0) a ,(select @pre :=-1) b
order by Score desc
解释
整理了一下几个不好理解的点:
-
@a 类似在 Oracle 中的rownum,可以在生成结果内附加上一列序列号,可以近似理解为查询后加上行号;
-
@a := @a + 1 实际上是赋值,旧值+1变为新值赋给@a;
-
实际上并没有直接 @a+1 那么简单,还要先去判断分数是否与前一行相同,所以引入 @pre 来记录:
- 先将Score赋值给: @pre := Score;
- 然后判断之前的 @pre 是否与赋值后的 @pre 不相同 ==> (@pre <> (@pre := Score)) “<>” 就是 "!=" 的意思;
- 两者不同,判断结果为真,则取1; 两者相同,判断结果为假,取0, 最后再用 0或1 加上 @a 即为当前行分数的排名;
-
(select @a := 0, @pre := -1) t 为初始化 @a 和 @pre 的开始值;
- @pre 初始值为 -1 为的是防止Score有 0 分的出现;
- @第一次比较Score值的时候,@pre初始值肯定和Score不同, 所以第一次比较 @a 必然会 +1,所以@a要从0开始;
-
最后以将结果根据Score进行倒序展示;
以上解释内容来自leetcode
cast好用,round,floor,并不行不知道为什么