leetcode178 分数排名 Rank Scores

编写一个 SQL查询来实现分数排名。如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有间隔

 创建表和数据:

Create table If Not Exists Scores (Id int,Score DECIMAL(3,2));
Truncate table Scores;
insert into Scores (Id, Score) values ('1','3.5');
insert into Scores (Id, Score) values ('2','3.65');
insert into Scores (Id, Score) values ('3','4.0');
insert into Scores (Id, Score) values ('4','3.85');
insert into Scores (Id, Score) values ('5','4.0');
insert into Scores (Id, Score) values ('6','3.65');

解法:

1.按Id和Score分组。每组中,大于等于每个Score的不同Score数目就是其排名。

select S1.Score,count(distinct S2.Score) as Rank
from Scores as S1 join Scores as S2 on (S1.Score <= S2.Score)
group by S1.Id,S1.Score
order by S1.Score desc

优化:

先将表中不同的score全部取出来,以子查询的方式完成。再与表连接,求 “大于等于每个Score的不同Score数目” 。依然要分组。

SELECT s1.Score, COUNT(s2.score) AS `Rank`
FROM Scores s1
JOIN
    (
        SELECT DISTINCT Score
        FROM Scores
        ORDER BY Score DESC
    ) AS s2 
ON (s1.Score <= s2.Score)
GROUP BY s1.Id,s1.Score
ORDER BY s1.Score desc

注意:FROM子句中关系的属性都可以在HAVING和SELECT子句中用聚集运算,但是只有出现在GROUP BY子句中的属性,才能以不聚集的方式出现在HAVING和SELECT子句中。

因此,上面的S1.ID可以不出现在SELECT子句中,S1.SCORE可以出现在SELECT子句中。其它字段不能以非聚集的方式出现在SELECT子句中。比如,S2.Score。

2.将“大于等于每个Score的不同Score数目”在子查询中实现,并不再分组。

select S1.Score,
    (select count(distinct S2.Score) 
     from Scores as S2 
     where S1.Score <= S2.Score
    ) as Rank
from Scores as S1
order by S1.Score desc;

 3.辅助变量

select score, @ran := @ran + (@pre <> (@pre := Score)) as rank 
from scores,(select @ran := 0, @pre := -1)  
order by score desc; 
  1. @ran 类似在 Oracle 中的rownum,可以在生成结果内附加上一列序列号,可以近似理解为查询后加上行号;

  2. @ran := @ran + 1 实际上是赋值,旧值+1变为新值赋给@a;

  3. 实际上并没有直接 @ran+1 那么简单,还要先去判断分数是否与前一行相同,所以引入 @pre 来记录:

    • 先将Score赋值给: @pre:= Score;
    • 然后判断之前的 @pre 是否与赋值后的@pre 不相同 ==> (@pre <> (@pre := Score)) “<>” 就是 "!=" 的意思;
    • 两者不同,判断结果为真,则取1; 两者相同,判断结果为假,取0, 最后再用 0或1 加上@ran 即为当前行分数的排名;
  4. (select @ran:= 0, @pre := -1) t 为初始化 @ran 和 @pre 的开始值;

    • @pre 初始值为 -1 为的是防止Score有 0 分的出现;
    • @pre第一次比较Score值的时候,@pre 初始值肯定和Score不同, 所以第一次比较 @ran 必然会 +1,所以@ran从0开始;
  5. 最后以将结果根据Score进行倒序展示;

猜你喜欢

转载自www.cnblogs.com/forever-fortunate/p/11722587.html
今日推荐