Поправете 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() в една заявка