I have three related tables:
- Course
- Student
- Teacher
Each course is given by a teacher to many students.
I can find the number of students attending a course:
SELECT c.id, count(*) FROM course as c, student as s
WHERE c.id = s.course_id
GROUP BY c.id;
I can find all the courses given by a teacher:
SELECT t.id, c.id FROM course as c, teacher as t
WHERE t.id = c.teacher_id;
I want to find how many students were taught by each teacher. Is the following query correct one?
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;
Unfortunately, I cannot test it directly because this is actually a simplification of the real problem at hand. I need to find out which solution works for the simplified problem.
To answer your question, no. You cannot reference
c.idinside the inline view aliased asx. That should throw an error.But if you remove that, then your query has the potential to return an inflated count, due to a semi-Cartesian product, between the inline view aliased as
xandc.So that predicate needs to be relocated, and you’d need to return c2.id from
x(i.e. add it to the SELECT list, you already have it referenced in the GROUP BY).This is equivalent to your query, just rewritten to replace the comma join operators and relocate join predicates to ON clause. This statement is equivalent to yours, and is invalid):
To fix that, add c2.id to the SELECT list in
x, and relocate that predicate. Something like this:Assuming that
idis UNIQUE and NOT NULL incourse, that query will return a reasonable count (although counts of zero will be “missing”).To return the “zero” counts, you’d need to use an OUTER join. And as I always prefer to use LEFT JOIN, the tables/inline views in the outermost query would need to be re-ordered:
Assuming that
idis a PRIMARY KEY (or equivalent UNIQUE and NOT NULL) on each table, then that will return a “correct” count.It’s not necessary to include the
coursetable in the inline view aliased asx. It would be sufficient to GROUP BY s.course_id.That query will return a valid “count”.
A simpler statement would easier to understand. Here’s how I would get the count: