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