我有三个相关的表格:
每个course
由teacher
提供给多个students
。
我可以找到参加课程的学生人数:
SELECT c.id, count(*) FROM course as c, student as s
WHERE c.id = s.course_id
GROUP BY c.id;
我可以找到老师给出的所有课程:
SELECT t.id, c.id FROM course as c, teacher as t
WHERE t.id = c.teacher_id;
我想找到每位老师教的学生人数。以下查询是否正确?
SELECT t.id, sum(x.count_s)
FROM
(SELECT count(*) AS count_s FROM course as c2, student as s
WHERE c2.id = s.course_id AND c2.id = c.id
GROUP BY c2.id) as x,
course as c, teacher as t
WHERE t.id = c.teacher_id;
不幸的是,我无法直接测试它,因为这实际上是对手头真正问题的简化。我需要找出适用于简化问题的解决方案。
答案 0 :(得分:3)
要回答你的问题,不。您无法在内嵌视图中引用c.id
别名为x
。那会引起错误。
但是如果你删除它,那么你的查询有可能在内联视图别名为x
和c
之间返回由于半笛卡尔积而导致的膨胀计数。
因此谓词需要重新定位,并且你需要从x
返回c2.id(即将它添加到SELECT列表,你已经在GROUP BY中引用了它。)
这相当于您的查询,只是重写以替换逗号连接运算符并将连接谓词重定位到ON子句。此声明与您的声明相同,并且无效):
SELECT t.id
, SUM(x.count_s)
FROM ( SELECT count(*) AS count_s
FROM course c2
JOIN student s
ON c2.id = s.course_id
AND c2.id = c.id -- INVALID here
GROUP
BY c2.id
) x
CROSS -- no join predicate
JOIN course c
JOIN teacher t
ON t.id = c.teacher_id
要解决此问题,请将c2.id添加到x
中的SELECT列表中,然后重新定位该谓词。像这样:
SELECT t.id
, SUM(x.count_s)
FROM ( SELECT count(*) AS count_s
, c2.id -- added
FROM course c2
JOIN student s
ON c2.id = s.course_id
-- AND c2.id = c.id -- relocated (removed from here)
GROUP
BY c2.id
) x
JOIN course c
ON x.id = c.id -- relocated (added here)
JOIN teacher t
ON t.id = c.teacher_id
假设id
中的course
是UNIQUE而非NULL,则该查询将返回合理的计数(尽管计数为零将“丢失”)。
要返回“零”计数,您需要使用OUTER连接。由于我总是喜欢使用LEFT JOIN,因此最外层查询中的表/内联视图需要重新排序:
SELECT t.id
, IFNULL(SUM(x.count_s),0)
FROM teacher t
LEFT
JOIN course c
ON c.teacher_id = t.id
LEFT
JOIN ( SELECT count(*) AS count_s
, c2.id -- added
FROM course c2
JOIN student s
ON c2.id = s.course_id
-- AND c2.id = c.id -- relocated (removed from here)
GROUP
BY c2.id
) x
ON x.id = c.id -- relocated (added here)
假设每个表上id
是一个PRIMARY KEY(或等效的UNIQUE和NOT NULL),那么它将返回一个“正确”的计数。
没有必要将course
表格包含在别名为x
的内联视图中。 GROUP BY s.course_id就足够了。
SELECT t.id
, IFNULL(SUM(x.count_s),0)
FROM teacher t
LEFT
JOIN course c
ON c.teacher_id = t.id
LEFT
JOIN ( SELECT count(*) AS count_s
, s.course_id
FROM student s
GROUP
BY s.course_id
) x
ON x.course_id = c.id -- relocated (added here)
该查询将返回有效的“计数”。
更简单的陈述更容易理解。以下是我如何计算:
SELECT t.id AS teacher_id
, COUNT(s.id) AS how_many_students_taught
FROM teacher t
LEFT
JOIN course c
ON c.id = t.course_id
LEFT
JOIN student s
ON s.course_id = c.id
GROUP
BY t.id
答案 1 :(得分:3)
您只需要在针对学生的课程中使用LEFT JOIN
,因为教师无法教授没有课程的学生。
SELECT a.id as Teacher_ID,
b.id as CourseID,
COUNT(c.studentID) totalStudents
FROM teacher a
INNER JOIN course b
ON b.teacher_ID = a.id
LEFT JOIN student c
ON b.id = c.course_ID
GROUP BY a.id, b.id
答案 2 :(得分:2)
假设你想要老师教过的不同学生数,那么这应该有效:
SELECT t.Id, COUNT(DISTINCT s.id)
FROM Teacher t
LEFT JOIN Course c ON t.id = c.teacher_id
LEFT JOIN Student s ON c.id = s.course_id
GROUP BY t.Id
但是,如果您想了解每位老师在每门课程中教授的学生人数,那么请尝试以下方法:
SELECT t.Id, c.Id, COUNT(DISTINCT s.id)
FROM Teacher t
LEFT JOIN Course c ON t.id = c.teacher_id
LEFT JOIN Student s ON c.id = s.course_id
GROUP BY t.Id, c.Id
祝你好运。