2

我有三个相关的表:

  • 课程
  • 学生
  • 老师

每个course都由 a teacherto many给出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;

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

4

3 回答 3

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
于 2013-02-06T00:00:32.460 回答
3

要回答你的问题,不。您不能c.id在别名为x. 那应该会引发错误。

x但是,如果您删除它,那么您的查询有可能在别名为和的内联视图之间返回一个夸大的计数,这是由于半笛卡尔积c

所以该谓词需要重新定位,并且您需要从返回 c2.id x(即,将其添加到 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 添加到 SELECT 列表中x,然后重新定位该谓词。像这样的东西:

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是 UNIQUE 并且 NOT NULL in course,该查询将返回一个合理的计数(尽管零计数将“丢失”)。

要返回“零”计数,您需要使用 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

于 2013-02-05T23:57:06.720 回答
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

祝你好运。

于 2013-02-05T23:57:10.853 回答