LeetCode每天一题

178.分数排名

题目:

178. 分数排名

难度中等

SQL架构

编写一个 SQL 查询来实现分数排名。

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

1
2
3
4
5
6
7
8
9
10
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+

例如,根据上述给定的 Scores 表,你的查询应该返回(按分数从高到低排列):

1
2
3
4
5
6
7
8
9
10
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+

重要提示:对于 MySQL 解决方案,如果要转义用作列名的保留字,可以在关键字之前和之后使用撇号。例如 Rank

解题思路

一:先对Score排序

怎么排序?看查询结果应该是需要逆序排序

order by Score desc

二:如何实现并列连续排名呢?

排名排名,我记得有四大排名函数。我们去网上搜搜看看都有哪些。

Sql 四大排名函数(ROW_NUMBER、RANK、DENSE_RANK、NTILE)

排名函数是Sql Server2005新增的功能

1.row_number:分组连续排名

row_number的用途的非常广泛,一般可以用来实现web程序的分页,他会为查询出来的每一行记录生成一个序号,依次排序且不会重复,注意使用row_number函数时必须要用over子句选择对某一列进行排序才能生成序号。

使用语法:

1
2
select row_number() over(order by 字段),字段,...
from 表名;

对上述题目使用

1
2
3
4
5
6
7
select row_number() over(order by Score) as Rank
from Scores;

输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 2], [3.85, 3], [3.65, 4], [3.65, 5], [3.50, 6]]}
2.rank:分组并列跳跃排名

RANK()函数,顾名思义排名函数,可以对某一个字段进行排名,这里为什么和ROW_NUMBER()不一样那,ROW_NUMBER()是排序,当存在相同成绩的学生时,ROW_NUMBER()会依次进行排序,他们序号不相同,而Rank()则不一样出现相同的,他们的排名是一样的。

使用语法:

1
2
select rank() over(order by 字段),字段,...
from 表名;

对上述题目使用

1
2
3
4
5
6
7
select Score,rank() over(order by Score desc) Rank
from Scores;

输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 3], [3.65, 4], [3.65, 4], [3.50, 6]]}
3.dense_rank:分组并列连续排名

DENSE_RANK()函数也是排名函数,和RANK()功能相似,也是对字段进行排名,DENSE_RANK()密集的排名他和RANK()区别在于,排名的连续性,DENSE_RANK()排名是连续的,RANK()是跳跃的排名,所以一般情况下用的排名函数就是RANK()。

使用语法:

1
2
select dense_rank() over(order by 字段),字段,...
from 表名;

对上述题目使用:

1
2
3
4
5
6
7
select Score,dense_rank() over(order by Score desc) Rank
from Scores;

输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 2], [3.65, 3], [3.65, 3], [3.50, 4]]}
4.ntile

NTILE()函数是将有序分区中的行分发到指定数目的组中,各个组有编号,编号从1开始,就像我们说的’分区’一样 ,分为几个区,一个区会有多少个 。

使用语法

1
2
select ntile(*) over(order by 字段),字段,...
from 表名; -- ntile(*) *号是代表要分为几个区

对上述题目使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 分为一个区
select Score,ntile(1) over(order by Score desc) 'Rank'
from Scores;

输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 1], [3.65, 1], [3.65, 1], [3.50, 1]]}

-- 分为两个区
select Score,ntile(2) over(order by Score desc) 'Rank'
from Scores;

输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 1], [3.65, 2], [3.65, 2], [3.50, 2]]}

答案解析

1
2
3
4
5
6
7
8
9
10
11
# Write your MySQL query statement below
select Score,dense_rank() over(order by Score desc) 'Rank'
from Scores


输入
{"headers": {"Scores": ["Id", "Score"]}, "rows": {"Scores": [[1, 3.50], [2, 3.65], [3, 4.00], [4, 3.85], [5, 4.00], [6, 3.65]]}}
输出
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 2], [3.65, 3], [3.65, 3], [3.50, 4]]}
预期结果
{"headers": ["Score", "Rank"], "values": [[4.00, 1], [4.00, 1], [3.85, 2], [3.65, 3], [3.65, 3], [3.50, 4]]}
点击查看

本文标题:LeetCode每天一题

文章作者:

发布时间:2020年07月12日 - 10:10:48

最后更新:2020年07月12日 - 20:19:51

原始链接:https://studentliuchang.gitee.io/%E6%AF%8F%E5%A4%A9%E4%B8%80%E9%81%93LeetCode%E9%A2%98-mysql-7.12/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------