Поправете LEFT JOIN
Това трябва да работи:
SELECT o.name AS organisation_name, count(e.id) AS total_used
FROM organisations o
LEFT JOIN exam_items e ON e.organisation_id = o.id
AND e.item_template_id = #{sanitize(item_template_id)}
AND e.used
GROUP BY o.name
ORDER BY o.name;
Имахте LEFT [OUTER] JOIN но по-късният WHERE условията го накараха да действа като обикновено [INNER] JOIN .
Преместете условието(ата) в JOIN клауза, за да работи по предназначение. По този начин само редове, които отговарят на всички тези условия, се съединяват на първо място (или колони от дясно таблицата се попълва с NULL). Както сте го имали, съединените редове се тестват за допълнителни условия практически след LEFT JOIN и се премахват, ако не преминат, точно както при обикновен JOIN .
count() никога не връща NULL като начало. Това е изключение сред агрегатните функции в това отношение. Следователно, никога има смисъл, дори и с допълнителни параметри. Ръководството:COALESCE(COUNT(col))
Трябва да се отбележи, че с изключение на
count, тези функции връщат нулева стойност, когато не са избрани редове.
Удебелен акцент мой. Вижте:
- Пребройте броя на атрибутите, които са NULL за ред
count() трябва да е в колона, дефинирана NOT NULL (като e.id ), или където условието за присъединяване гарантира NOT NULL (e.organisation_id , e.item_template_id , или e.used ) в примера.
Тъй като used е тип boolean , изразът e.used = true е шум, който изгаря само до e.used .
Тъй като o.name не е дефиниран UNIQUE NOT NULL , може да искате да GROUP BY o.id вместо това (id като ПК) - освен ако не възнамерявате за сгъване на редове със същото име (включително NULL).
Първо обобщете, присъединете се по-късно
Ако повечето или всички редове от exam_items се отчитат в процеса, тази еквивалентна заявка обикновено е значително по-бърза / по-евтина:
SELECT o.id, o.name AS organisation_name, e.total_used
FROM organisations o
LEFT JOIN (
SELECT organisation_id AS id -- alias to simplify join syntax
, count(*) AS total_used -- count(*) = fastest to count all
FROM exam_items
WHERE item_template_id = #{sanitize(item_template_id)}
AND used
GROUP BY 1
) e USING (id)
ORDER BY o.name, o.id;
(Това се предполага, че не искате да сгъвате редове със същото име, както е споменато по-горе – типичният случай.)
Сега можем да използваме по-бързия / по-прост count(*) в подзаявката и не се нуждаем от GROUP BY във външния SELECT .
Вижте:
- Множество извиквания на array_agg() в една заявка