When involving all rows or major parts of the "many" table, it's typically faster to aggregate first and join later. Certainly the case here, since we are after counts for "each department", and there is no WHERE
clause at all.
SELECT d.name, COALESCE(e.ct, 0) AS nr_employees
FROM department d
LEFT JOIN (
SELECT department_id AS id, count(*) AS ct
FROM employee
GROUP BY department_id
) e USING (id);
Also made it a LEFT [OUTER] JOIN
, to keep departments without any employees in the result. And COALESCE
to report 0
employees instead of NULL
in that case.
Related, with more explanation:
Your original query would work too, after fixing the GROUP BY
clause:
SELECT department.name, COUNT(employee.id)
FROM department
INNER JOIN employee ON department.id = employee.department_id
Group BY department.id; --!
That's assuming department.id
is the PRIMARY KEY
of the table, in which case it covers all columns of that table, including department.name
. And you may want LEFT JOIN
like above.
Aside: Consider legal, lower-case names exclusively in Postgres. See: