三个相关表中记录数的总和

时间:2013-02-05 23:52:42

标签: mysql sql sum subquery

我有三个相关的表格:

  • 学生
  • 教师

每个courseteacher提供给多个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;

不幸的是,我无法直接测试它,因为这实际上是对手头真正问题的简化。我需要找出适用于简化问题的解决方案。

3 个答案:

答案 0 :(得分:3)

要回答你的问题,不。您无法在内嵌视图中引用c.id别名为x。那会引起错误。

但是如果你删除它,那么你的查询有可能在内联视图别名为xc之间返回由于半笛卡尔积而导致的膨胀计数。

因此谓词需要重新定位,并且你需要从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
祝你好运。