问题描述:编写一个 SQL 查询来实现分数排名。如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。
样例数据如下:
Id | Score |
---|---|
1 | 3.50 |
2 | 3.65 |
3 | 4.00 |
4 | 3.85 |
5 | 4.00 |
6 | 3.65 |
排序过后:
Score | Rank |
---|---|
4.00 | 1 |
4.00 | 1 |
3.85 | 2 |
3.65 | 3 |
3.65 | 3 |
3.50 | 4 |
思考线路:
sequenceDiagram
常规思路:dense_rank()->>Mysql模拟dense_rank()
特色思路:大喊一声:还有谁?懂了吗?O(∩_∩)O哈哈~
思路解析:
1.常规方案:
根据问题描述,其表达的意思很符合Oracle中的一个排序函数dense_rank(),但Mysql中并不存在这样直接可以使用的函数。因此需要手动模拟。
手动模拟语句(市面上常见的语句):
select Score,
case when @preScore = Score then @curerank
else @curerank := @curerank + 1
end as RANK,@preScore := Score AS preScore
from Scores s,(select @curerank := 0,@preScore := NULL) r
order by Score desc
但上述的语句并不符合LeetCode的评判标准,因为其运行会产生如下的结果,注意在我的答案中的RANK数据是被视为字符,而非整型,因此我们需要将其格式进行转换。
怎么转换的?外套一层+cast函数就可以。具体SQL可以参照下面:
select Score,CAST(RANK AS UNSIGNED) Rank
from
(select Score,
case when @preScore = Score then @curerank
else @curerank := @curerank + 1
end as RANK,@preScore := Score
from Scores s,(select @curerank := 0,@preScore := NULL) r
order by Score desc) temp
2.特色方案:
就像在擂台上一样,很嚣张的喊道:还有谁?!!的感觉。其具体思路就是去重统计比当前分数还高的数据量,分数低的,比他高的人就多,那么反过来高手就寂寞了,count就少了,排名自然就高了。具体SQL如下,至于是用>搭配+1,还是>=看你的习惯,当然>=的效率是高于>的。
SELECT a.score,
(SELECT count(DISTINCT score)
FROM Scores
WHERE Score > a.score)+1 AS rank
FROM Scores a
ORDER BY rank
总结:第一种方案是一种习惯性的思维导向,第二种则是一种活用规则的、非常灵巧的设计方案。个人还是很喜欢第二种方案,当然第一种的方案可以拓展你知识点的宽度。