最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用SQL子查询找出选修了所有课程的优等生名单?
时间:2026-07-02 11:16:45 编辑:袖梨 来源:一聚教程网
直接用IN或EXISTS无法表达“选过所有课程”的逻辑,因其仅判断集合包含关系;正确解法是分组统计每个学生选课数并与有效课程总数比对,需用COUNT(DISTINCT course_id)并同步过滤课程状态。
为什么直接用 IN 或 EXISTS 子查询不行?
很多人一上来就写 SELECT student_id FROM enrollments WHERE course_id IN (SELECT course_id FROM courses),结果得到的是“选过任意课程”的学生,而不是“选过所有课程”的人。核心在于:子查询必须表达“对每门课都存在对应选课记录”,不是简单集合包含关系。
用 COUNT(DISTINCT ...) + 分组比对是最稳的解法
前提是:学生-课程关系存于 enrollments 表(字段为 student_id, course_id),课程总数可查得。关键思路是——算出每个学生选了多少门课,再和总课程数比对是否相等。
- 先确认总课程数:
SELECT COUNT(*) FROM courses - 再分组统计每个学生的选课数:
SELECT student_id, COUNT(DISTINCT course_id) AS cnt FROM enrollments GROUP BY student_id - 最后用
HAVING筛出等于总课程数的:HAVING cnt = (SELECT COUNT(*) FROM courses)
注意必须用 COUNT(DISTINCT course_id),避免同一学生重复选同一门课导致计数虚高。
如果还要加“优等生”条件(比如 GPA ≥ 90),别在子查询里硬塞
把成绩筛选和“选全课程”拆开做,否则容易漏数据或逻辑错乱。典型错误是写成 WHERE gpa >= 90 AND student_id IN (SELECT ...),但子查询里没关联成绩表,student_id 可能根本不在成绩表中。
- 正确做法:先用上一步拿到“选全课程”的
student_id列表,再和students或grades表JOIN - 例如:
SELECT s.name FROM students s JOIN (SELECT student_id FROM enrollments GROUP BY student_id HAVING COUNT(DISTINCT course_id) = (SELECT COUNT(*) FROM courses)) t ON s.id = t.student_id WHERE s.gpa >= 90 - 如果
gpa存在另一张表(如grades),记得JOIN时处理可能的NULL——用INNER JOIN自然过滤掉无成绩者,比LEFT JOIN + WHERE gpa IS NOT NULL更安全
遇到课程表有状态字段(如 is_active = 1)时,子查询里的 COUNT 必须同步过滤
否则会拿“全部课程数”去比,但学生实际只需选完当前有效的课。常见坑是子查询里忘了加 WHERE is_active = 1,导致本该入围的学生被筛掉。
- 总课程数要改成:
(SELECT COUNT(*) FROM courses WHERE is_active = 1) - 学生选课统计也要限制课程有效性:
COUNT(DISTINCT CASE WHEN c.is_active = 1 THEN e.course_id END),或者更干脆——先JOIN courses再WHERE c.is_active = 1 - 别依赖外层
WHERE过滤课程状态,因为分组统计必须基于同一有效课程集
多一层状态判断,就多一个对齐点;漏掉任何一个,结果就偏了。
相关文章
- 培训宝如何进行考勤打卡-培训宝线上培训签到步骤全流程解析 07-02
- 点淘粉丝团如何加入 07-02
- procreate如何翻转画布 07-02
- 国家数字图书馆官网入口在哪里-国家数字图书馆如何免费阅读网页版 07-02
- 婚姻挽回的终极秘诀 07-02
- 网上租办公室完整攻略 07-02