每个学生的最高成绩:并列取课程号最小的
LeetCode 1112 · 分组取首行、多字段排序
面试怎么回答
ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade DESC, course_id) 取 rn = 1,第二排序键 course_id 解决并列,外层再 ORDER BY student_id。并列规则写进排序键,结果才是确定的。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
选课表记录学生、课程和成绩。找出每个学生成绩最高的一门课和成绩;成绩并列时取课程号最小的那门;结果按学生 ID 升序。
表结构
- Enrollments:student_id、course_id、grade;(student_id, course_id) 为主键
思路
按学生分区,先按成绩降序、再按课程号升序排,取第一行。因为排序键已经能唯一确定一行,用 ROW_NUMBER 更贴切。原解法漏了题目要求的「按学生 ID 排序」。
参考解法
select student_id,course_id ,grade
from (
select student_id,course_id ,grade,
rank()over(partition by student_id order by grade desc,course_id) rK
from Enrollments
)t1
where rk =1
另一种写法:ROW_NUMBER + 外层排序
SELECT student_id, course_id, grade
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY grade DESC, course_id) AS rn
FROM Enrollments
) t
WHERE rn = 1
ORDER BY student_id
易错点
- 只按成绩排序时并列结果不确定,必须加上 course_id 作为第二排序键。
- 别忘了外层 ORDER BY student_id。