LeetCode-MySQL: 178.分数排名

题目描述

编写一个 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 s1.Score, count(distinct(s2.Score)) Rank
from Scores s1, Scores s2
where s1.Score<=s2.Score
group by s1.Id
order by Rank;

想了几分钟,有点懵~,s1.Score<=s2.Score 是啥意思?

这个题解有好几个地方不明白是啥意思,当然关键点还是 where s1.Score<=s2.Score 不明白。

接下来我会在本地还原这个题解的执行过程,一步步分析 where s1.Score<=s2.Score 到底做了什么。

创建表 scores

CREATE TABLE `scores` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `score` int(3)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

向表 scores 添加一些测试数据

INSERT INTO `scores` (`score`) values (100), (80), (80), (60);

查询scores表,目前共有4条记录

LeetCode-MySQL: 178.分数排名

 让我们来看看 select * from scores s1, scores s2 的返回结果是什么

LeetCode-MySQL: 178.分数排名

 

 

                                  

 

 

 

 

 

 

 

 

 

 

返回的结果集共有16条记录。

这种多表查询又称 “笛卡尔查询",结果集的列数是s1表和s2表的列数之和,行数是s1表和s2表的行数之积。

到了这里就会自然地想到: select * from scores s1, scores s2 where s1.score <= s2.score 的返回结果是什么呢?

LeetCode-MySQL: 178.分数排名

 这个结果是怎么得到的呢?我想到了这里大家应该都知道了

LeetCode-MySQL: 178.分数排名

是的,如上图,左边是s1表,右边是s2表。

现在我们已经知道了 select * from scores s1, scores s2 where s1.score <= s2.score 的返回结果,再进行 group by,order by 和 count() 就很好分析了。

给 scores 表排名:

select s1.score, count(distinct(s2.score)) rank  from scores s1, scores s2 where s1.score <= s2.score group by s1.id order by rank

LeetCode-MySQL: 178.分数排名

group by s1.id:根据 s1.id 进行分组

count(distinct(s2.score)):distinct(s2.score)去重,count(distinct(s2.score))在分组的过程中计算 每个分组 对 s2.score去重后 的记录条数

分析到这里,我们已经清楚排名是怎么计算出来的了。但是,我们可能仍然会有一些疑惑,不禁会想:为什么这样做可以计算出排名?

思考

回想曾经考试后班级的排名,我们是怎么对学生进行排名的呢?

每个人都要和其他所有人进行比较,如果分数比所有人都高,则排第一名。

如下图,

LeetCode-MySQL: 178.分数排名

LeetCode-MySQL: 178.分数排名

 

 

 

 

 

 

 

 

 

 

可以看到, s1.score<=s2.score  就是对班级排名的一次过程模拟。

老实说,这个题解感觉不是那么好理解,或许是自己真的太笨了吧~

另一个题解

select a.Score as Score,
(select count(distinct b.Score) from Scores b where b.Score >= a.Score) as Rank
from Scores a
order by a.Score DESC

作者:johnbear007
链接:https://leetcode-cn.com/problems/rank-scores/solution/fen-cheng-liang-ge-bu-fen-xie-hui-rong-yi-hen-duo-/
来源:力扣(LeetCode)

个人感觉这个题解好理解多了,非常清晰明了。

LeetCode-MySQL: 178.分数排名

上一篇:[elasticsearch同步数据库]Elasticsearch 同步mysql数据


下一篇:plsql下载&安装&汉化&使用的详细教程