MySQL: GROUP BY + HAVING MAX(...) --- 为什么 HAVING MAX(grade) 不会 return maximum grade?
MySQL: GROUP BY + HAVING MAX(...) --- Why HAVING MAX(grade) will not return maximum grade?
学分 Leetcode 1112. 每个学生的最高成绩
要求:编写一个SQL查询,为每个学生找到最高分及其对应的课程。如果出现平局,您应该找到 course_id 最小的课程。输出必须按递增 student_id.
排序
查询结果格式如下例:
Enrollments table:
+------------+-------------------+
| 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 |
+------------+-----------+-------+
Result table:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 1 | 2 | 99 |
| 2 | 2 | 95 |
| 3 | 3 | 82 |
为什么这行不通?
select student_id, course_id, grade
from enrollments
group by student_id
having max(grade)
order by student_id
我认为 return 应该是 {"headers": ["student_id", "course_id", "grade"], "values": [[1, 2, 99], [2, 2, 95], [3, 3, 82]]};然而,实际的 return 是 {"headers": ["student_id", "course_id", "grade"], "values": [[1, 1, 90], [2, 2, 95], [3, 1, 80]]}.
如果有人能帮助我,非常感谢!
看起来您需要在 FROM 子句中使用子查询来处理双 GROUP BY。
在下面的查询中,子查询获取每个用户的最大成绩,然后外部注册 table 在 student_id 和成绩上加入。然后它在外部查询中获取第一个 course_id。
SELECT e.student_id, min(e.course_id) course_id, e.grade
FROM enrollments e
JOIN (
SELECT student_id, max(grade) grade
FROM enrollments
GROUP BY student_id) g USING (student_id, grade)
GROUP BY e.studentId;
也许你认为这个条件:
having max(grade)
是一条指令,因此只应返回每个 studentid
具有最高成绩的行。
这不是 HAVING
子句的作用。
它是一种在聚合完成后过滤聚合数据的方法,当它在 GROUP BY
子句之后使用时。
HAVING
子句接受 1 个或多个计算结果为 TRUE
或 FALSE
的布尔表达式。
所以在这种情况下 max(grade)
不是布尔表达式(尽管对于 MySql 任何数字表达式都可以用来代替布尔表达式)。
我知道您希望在结果中显示每个 studentid
.
最高成绩的行
这可以使用 MySQL 8.0 中的 window 函数以最有效和最高效的方式完成:ROW_NUMBER()
或 RANK()
如果您还想返回关系:
select e.student_id, e.course_id, e.grade
from (
select *, row_number() over (partition by student_id order by grade desc) rn
from Enrollments
) e
where e.rn = 1
参见demo。
结果:
| student_id | course_id | grade |
| ---------- | --------- | ----- |
| 1 | 2 | 99 |
| 2 | 2 | 95 |
| 3 | 3 | 82 |
这是一个典型的top-1-per-group问题。解决这个问题的关键在于,既然要整条记录,就不要想聚合,而是过滤.
我会为此推荐一个相关的子查询。这是一个可移植的解决方案,适用于大多数数据库(包括不支持 window 函数的 MySQL 5.x 版本)。有了正确的索引,这通常是一种非常有效的方法。
select e.*
from enrollments e
where e.grade = (
select max(e1.grade)
from enrollments e1
where e1.student_id = e.student_id
)
这里你要的索引是(student_id, grade)
.
学分 Leetcode 1112. 每个学生的最高成绩
要求:编写一个SQL查询,为每个学生找到最高分及其对应的课程。如果出现平局,您应该找到 course_id 最小的课程。输出必须按递增 student_id.
排序查询结果格式如下例:
Enrollments table:
+------------+-------------------+
| 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 |
+------------+-----------+-------+
Result table:
+------------+-------------------+
| student_id | course_id | grade |
+------------+-----------+-------+
| 1 | 2 | 99 |
| 2 | 2 | 95 |
| 3 | 3 | 82 |
为什么这行不通?
select student_id, course_id, grade
from enrollments
group by student_id
having max(grade)
order by student_id
我认为 return 应该是 {"headers": ["student_id", "course_id", "grade"], "values": [[1, 2, 99], [2, 2, 95], [3, 3, 82]]};然而,实际的 return 是 {"headers": ["student_id", "course_id", "grade"], "values": [[1, 1, 90], [2, 2, 95], [3, 1, 80]]}.
如果有人能帮助我,非常感谢!
看起来您需要在 FROM 子句中使用子查询来处理双 GROUP BY。
在下面的查询中,子查询获取每个用户的最大成绩,然后外部注册 table 在 student_id 和成绩上加入。然后它在外部查询中获取第一个 course_id。
SELECT e.student_id, min(e.course_id) course_id, e.grade
FROM enrollments e
JOIN (
SELECT student_id, max(grade) grade
FROM enrollments
GROUP BY student_id) g USING (student_id, grade)
GROUP BY e.studentId;
也许你认为这个条件:
having max(grade)
是一条指令,因此只应返回每个 studentid
具有最高成绩的行。
这不是 HAVING
子句的作用。
它是一种在聚合完成后过滤聚合数据的方法,当它在 GROUP BY
子句之后使用时。
HAVING
子句接受 1 个或多个计算结果为 TRUE
或 FALSE
的布尔表达式。
所以在这种情况下 max(grade)
不是布尔表达式(尽管对于 MySql 任何数字表达式都可以用来代替布尔表达式)。
我知道您希望在结果中显示每个 studentid
.
最高成绩的行
这可以使用 MySQL 8.0 中的 window 函数以最有效和最高效的方式完成:ROW_NUMBER()
或 RANK()
如果您还想返回关系:
select e.student_id, e.course_id, e.grade
from (
select *, row_number() over (partition by student_id order by grade desc) rn
from Enrollments
) e
where e.rn = 1
参见demo。
结果:
| student_id | course_id | grade |
| ---------- | --------- | ----- |
| 1 | 2 | 99 |
| 2 | 2 | 95 |
| 3 | 3 | 82 |
这是一个典型的top-1-per-group问题。解决这个问题的关键在于,既然要整条记录,就不要想聚合,而是过滤.
我会为此推荐一个相关的子查询。这是一个可移植的解决方案,适用于大多数数据库(包括不支持 window 函数的 MySQL 5.x 版本)。有了正确的索引,这通常是一种非常有效的方法。
select e.*
from enrollments e
where e.grade = (
select max(e1.grade)
from enrollments e1
where e1.student_id = e.student_id
)
这里你要的索引是(student_id, grade)
.