596. 超过5名学生的课

难度:简单 | 题号:596 | 链接:596. 超过 5 名学生的课 - 力扣(LeetCode) | 数据结构:SQL

关联:订单最多的用户(同为「分组计数 + 过滤」)· 查询近30天活跃用户数(分组去重计数)· 可对照 SQL原理_02(GROUP BY / HAVING / WHERE 与 HAVING 的区别)。

🎯 问题描述

描述:查询至少有 5 名学生的所有课程(班级)。结果以任意顺序返回。

表:Courses

1
2
3
4
5
6
7
8
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| student | varchar |
| class | varchar |
+-------------+---------+
(student, class) 是该表的联合主键(不同值的列的组合)。
该表的每一行表示学生的名字和他们注册的课程。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
输入:
Courses table:
+---------+----------+
| student | class |
+---------+----------+
| A | Math |
| B | English |
| C | Math |
| D | Biology |
| E | Math |
| F | Computer |
| G | Math |
| H | Math |
| I | Math |
+---------+----------+
输出:
+---------+
| class |
+---------+
| Math |
+---------+
解释:
- Math 课有 6 名学生,包含它。
- English / Biology / Computer 各只有 1 名学生,不包含。

提示:

  • 先按 class 分组计数,再对分组结果过滤 → 必须用 HAVING,不能用 WHERE(WHERE 在分组之前过滤行,看不到 COUNT)。
  • 题目提示「同一学生在同一课程中不应被重复计算」→ 本表 (student, class) 是联合主键天然去重,COUNT(*) 即可;但写 COUNT(DISTINCT student) 更防御(防止数据重复时误算)。
  • HAVING 中不能引用列别名(HAVING cnt >= 5 会报 Unknown column),要写完整聚合表达式 COUNT(*) >= 5。

💻 解题思路

思路1:GROUP BY + HAVING(用户解法)

核心逻辑

按 class 分组,COUNT(*) 数出每门课的学生数,HAVING COUNT(*) >= 5 筛出人数达标的课程。

代码实现

1
2
3
4
5
# Write your MySQL query statement below
SELECT class
FROM Courses
GROUP BY class
HAVING COUNT(*) >= 5;

💡 更防御的写法(同一学生重复选课时也正确):

1
2
3
4
SELECT class
FROM Courses
GROUP BY class
HAVING COUNT(DISTINCT student) >= 5;

📊 性能分析

  • 时间复杂度:O(n)O(n)(全表扫描 + 哈希分组;class 上有索引可加速分组)。
  • 空间复杂度:O(c)O(c),cc 为课程数。

思考

  • WHERE vs HAVING —— 本题最核心的考点:
    • WHERE 作用于原始行,在 GROUP BY 之前执行,用不了聚合函数;
    • HAVING 作用于分组后的结果,在 GROUP BY 之后执行,专门用来筛选聚合值。
    • 口诀:「行级条件走 WHERE,组级条件走 HAVING」。
  • 别把 student_count 当别名用在 HAVING 里:SELECT class, COUNT(*) AS cnt ... HAVING cnt >= 5 在 MySQL 里会报 Error 1054: Unknown column 'cnt' in 'having clause'(HAVING 的求值早于 SELECT 别名解析)→ 必须重写 COUNT(*)。
  • COUNT(*) 还是 COUNT(DISTINCT student):依赖联合主键去重时二者等价;若表可能存在重复插入了同一 (student, class),只有 DISTINCT 版才正确。工程里宁可多写 DISTINCT。

🔗 相关链接

  • 所属 MOC:学习-数据结构与算法MOC
  • 题集索引:LeetCode题集索引
  • 关联概念:SQL原理_02(分组过滤 / WHERE 与 HAVING)
  • 同类题目:订单最多的用户(HAVING 计数)· 查询近30天活跃用户数(COUNT(DISTINCT ...))

📝 总结

「分组后按计数过滤」模板:

  • GROUP BY 分组列 HAVING COUNT(...) >= N,一句话即得。
  • 三个关键点:① 组级条件用 HAVING,别用 WHERE;② HAVING 里不能引别名,写全 COUNT(*);③ 人数类统计优先 COUNT(DISTINCT 学生) 防重复数据。

🔗 题集索引:LeetCode题集索引 · 算法地图:学习-数据结构与算法MOC
📎 同类题:订单最多的用户 · 查询近30天活跃用户数 | 概念:SQL原理_02