题目描述

(通过次数14,777 | 提交次数22,508,通过率65.65%)

表:Enrollments
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| course_id | int |
| grade | int |
+---------------+---------+
(student_id, course_id) 是该表的主键。
编写一个 SQL 查询,查询每位学生获得的最高成绩和它所对应的科目,若科目成绩并列,取course_id最小的一门。查询结果需按student_id增序进行排序。
以 任意顺序 返回结果表。
查询结果格式如下所示。
示例 1
输入:
Enrollments 表:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 2 | 2 | 95 |
| 2 | 3 | 95 |
| 1 | 1 | 90 |
| 1 | 2 | 99 |
| 3 | 1 | 80 |
| 3 | 2 | 75 |
| 3 | 3 | 82 |
+------------+-----------+-------+
输出:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 1 | 2 | 99 |
| 2 | 2 | 95 |
| 3 | 3 | 82 |
+------------+-----------+-------+
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/highest-grade-for-each-student
表:Enrollments +---------------+---------+ | Column Name | Type | +---------------+---------+ | student_id | int | | course_id | int | | grade | int | +---------------+---------+ (student_id, course_id) 是该表的主键。 编写一个 SQL 查询,查询每位学生获得的最高成绩和它所对应的科目,若科目成绩并列,取course_id最小的一门。查询结果需按student_id增序进行排序。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 输入: Enrollments 表: +------------+-------------------+ | student_id | course_id | grade | +------------+-----------+-------+ | 2 | 2 | 95 | | 2 | 3 | 95 | | 1 | 1 | 90 | | 1 | 2 | 99 | | 3 | 1 | 80 | | 3 | 2 | 75 | | 3 | 3 | 82 | +------------+-----------+-------+ 输出: +------------+-------------------+ | student_id | course_id | grade | +------------+-----------+-------+ | 1 | 2 | 99 | | 2 | 2 | 95 | | 3 | 3 | 82 | +------------+-----------+-------+ 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/highest-grade-for-each-student
表:Enrollments
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| student_id    | int     |
| course_id     | int     |
| grade         | int     |
+---------------+---------+
(student_id, course_id) 是该表的主键。

编写一个 SQL 查询,查询每位学生获得的最高成绩和它所对应的科目,若科目成绩并列,取course_id最小的一门。查询结果需按student_id增序进行排序。
以 任意顺序 返回结果表。

查询结果格式如下所示。
示例 1:
输入:
Enrollments 表:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 2          | 2         | 95    |
| 2          | 3         | 95    |
| 1          | 1         | 90    |
| 1          | 2         | 99    |
| 3          | 1         | 80    |
| 3          | 2         | 75    |
| 3          | 3         | 82    |
+------------+-----------+-------+
输出:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 1          | 2         | 99    |
| 2          | 2         | 95    |
| 3          | 3         | 82    |
+------------+-----------+-------+

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/highest-grade-for-each-student
//测试数据
Create table If Not Exists Enrollments (student_id int, course_id int, grade int);
insert into Enrollments (student_id, course_id, grade) values ('2', '2', '95');
insert into Enrollments (student_id, course_id, grade) values ('2', '3', '95');
insert into Enrollments (student_id, course_id, grade) values ('1', '1', '90');
insert into Enrollments (student_id, course_id, grade) values ('1', '2', '99');
insert into Enrollments (student_id, course_id, grade) values ('3', '1', '80');
insert into Enrollments (student_id, course_id, grade) values ('3', '2', '75');
insert into Enrollments (student_id, course_id, grade) values ('3', '3', '82');
//测试数据 Create table If Not Exists Enrollments (student_id int, course_id int, grade int); insert into Enrollments (student_id, course_id, grade) values ('2', '2', '95'); insert into Enrollments (student_id, course_id, grade) values ('2', '3', '95'); insert into Enrollments (student_id, course_id, grade) values ('1', '1', '90'); insert into Enrollments (student_id, course_id, grade) values ('1', '2', '99'); insert into Enrollments (student_id, course_id, grade) values ('3', '1', '80'); insert into Enrollments (student_id, course_id, grade) values ('3', '2', '75'); insert into Enrollments (student_id, course_id, grade) values ('3', '3', '82');
//测试数据
Create table If Not Exists Enrollments (student_id int, course_id int, grade int);

insert into Enrollments (student_id, course_id, grade) values ('2', '2', '95');
insert into Enrollments (student_id, course_id, grade) values ('2', '3', '95');
insert into Enrollments (student_id, course_id, grade) values ('1', '1', '90');
insert into Enrollments (student_id, course_id, grade) values ('1', '2', '99');
insert into Enrollments (student_id, course_id, grade) values ('3', '1', '80');
insert into Enrollments (student_id, course_id, grade) values ('3', '2', '75');
insert into Enrollments (student_id, course_id, grade) values ('3', '3', '82');

解题思路

这是一道非常典型的开窗函数使用场景的题目。
题目要求:查询每位学生获得的最高成绩和它所对应的科目。若科目成绩并列,取course_id最小的一门。
本质上来说,这是一个去重的操作。
去重操作有两点需要明确:
第一:按什么字段去重(去重的KEY)?
题目要求:查询每位学生的数据,一个学生一条件结果。那么,很明显。这里的KEY是student_id。
在使用开窗函数时,KEY值被写在partition by的后面。
第二:当多条记录的KEY相同时,按什么规则取出唯一的一条(去重规则)?
题目要求:一个学生有多条数据时,查询出成绩最高的那一条。如果存在多门课程并列第一的情况时,取课程ID(course_id)的值最小的那一条。
在使用开窗函数时,去重规则写在order by的后面。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
select
student_id,
course_id,
grade
from (
select
student_id,
course_id,
grade,
row_number() over(partition by student_id order by grade desc,course_id) rn
from Enrollments
)a
where rn = 1;
select student_id, course_id, grade from ( select student_id, course_id, grade, row_number() over(partition by student_id order by grade desc,course_id) rn from Enrollments )a where rn = 1;
select
    student_id,
    course_id,
    grade
from (
    select
        student_id,
        course_id,
        grade,
        row_number() over(partition by student_id order by grade desc,course_id) rn
    from Enrollments
)a
where rn = 1;

picture loss