编写一个 SQL查询来实现分数排名。若是两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不该该有“间隔”。优化
建立表和数据:spa
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');
解法:code
1.按Id和Score分组。每组中,大于等于每一个Score的不一样Score数目就是其排名。blog
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;
优化:table
先将表中不一样的score所有取出来,以子查询的方式完成。再与表链接,求 “大于等于每一个Score的不一样Score数目” 。依然要分组。class
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。select
2.将“大于等于每一个Score的不一样Score数目”在子查询中实现,并再也不分组。im
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;
@ran 相似在 Oracle 中的rownum,能够在生成结果内附加上一列序列号,能够近似理解为查询后加上行号;
@ran := @ran + 1 其实是赋值,旧值+1变为新值赋给@a;
实际上并无直接 @ran+1 那么简单,还要先去判断分数是否与前一行相同,因此引入 @pre 来记录:
(select @ran:= 0, @pre := -1) t 为初始化 @ran 和 @pre 的开始值;
最后以将结果根据Score进行倒序展现;