学生参加各科考试的次数:先做全组合再计数
LeetCode 1280 · CROSS JOIN 补全组合、LEFT JOIN 计数
面试怎么回答
Students CROSS JOIN Subjects 得到全部组合,再 LEFT JOIN Examinations,按学生和科目分组 COUNT(e.subject_name)。先用笛卡尔积补全维度组合、再左关联事实,是做「补零报表」的标准方法。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
学生表、科目表、考试记录表。输出每个学生在每门科目上参加考试的次数,没考过的科目也要输出 0。按学生 ID、科目名排序。
表结构
- Students:student_id(主键)、student_name
- Subjects:subject_name(主键)
- Examinations:student_id、subject_name;可能有重复行
思路
结果要覆盖「每个学生 × 每门科目」的所有组合,这些组合在考试表里不一定都有,所以先用 CROSS JOIN 构造完整组合,再 LEFT JOIN 考试记录,按组合分组用 COUNT(考试表的列) 计数,没有考试的组合计为 0。
参考解法
SELECT a.student_id, a.student_name, b.subject_name, COUNT(e.subject_name) AS attended_exams
FROM Students a CROSS JOIN Subjects b
LEFT JOIN Examinations e ON a.student_id = e.student_id AND b.subject_name = e.subject_name
GROUP BY a.student_id, b.subject_name
ORDER BY a.student_id, b.subject_name
易错点
- 直接从考试表分组,没考过的科目不会出现。
- 用 COUNT(*) 会把没有考试的组合计成 1。