Opravte LEFT JOIN
Mělo by to fungovat:
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;
Měli jste LEFT [OUTER] JOIN ale pozdější WHERE podmínky způsobily, že to funguje jako prosté [INNER] JOIN .
Přesuňte podmínky do JOIN klauzule, aby to fungovalo tak, jak bylo zamýšleno. Tímto způsobem se na prvním místě spojí pouze řádky, které splňují všechny tyto podmínky (nebo sloupce z zprava tabulka je vyplněna NULL). Jak jste to měli vy, spojené řádky jsou prakticky po testovány na další podmínky LEFT JOIN a odstraněny, pokud neprojdou, stejně jako u obyčejného JOIN .
count() pro začátek nikdy nevrátí NULL. V tomto ohledu je to výjimka mezi agregovanými funkcemi. Proto nikdy dává smysl i s dalšími parametry. Manuál:COALESCE(COUNT(col))
Je třeba poznamenat, že s výjimkou
count, tyto funkce vrátí hodnotu null, pokud nejsou vybrány žádné řádky.
Odvážný důraz můj. Viz:
- Spočítejte počet atributů, které mají hodnotu NULL na řádku
count() musí být ve sloupci definovaném NOT NULL (jako e.id ), nebo kde podmínka spojení zaručuje NOT NULL (e.organisation_id , e.item_template_id , nebo e.used ) v příkladu.
Od used je typu boolean , výraz e.used = true je šum, který se spálí na pouhé e.used .
Od o.name není definováno UNIQUE NOT NULL , možná budete chtít GROUP BY o.id místo toho (id být PK) – pokud to nemáte v úmyslu pro skládání řádků se stejným názvem (včetně NULL).
Nejprve agregujte, připojte se později
Pokud většina nebo všechny řádky exam_items se v procesu započítávají, tento ekvivalentní dotaz je obvykle podstatně rychlejší / levnější:
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;
(Předpokládáme, že nechcete skládat řádky se stejným názvem, jak je uvedeno výše – typický případ.)
Nyní můžeme použít rychlejší / jednodušší count(*) v poddotazu a nepotřebujeme žádný GROUP BY ve vnějším SELECT .
Viz:
- Více volání array_agg() v jednom dotazu