2

関連するテーブルが3つあります。

  • コース
  • 学生
  • 先生

それぞれがaからmanyにcourse与えられます。teacherstudents

コースに参加している学生の数を見つけることができます:

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

あなたの質問に答えるために、いいえ。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であると仮定すると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それが各テーブルのPRIMARYKEY(または同等のUNIQUEおよびNOT NULL)であると仮定すると、「正しい」カウントが返されます。

courseとしてエイリアスされたインラインビューにテーブルを含める必要はありませんx。GROUPBYs.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 に答える
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 に答える
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 に答える