Ret LEFT JOIN
Dette burde virke:
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;
Du havde en LEFT [OUTER] JOIN
men den senere WHERE
betingelser fik den til at fungere som en almindelig [INNER] JOIN
.
Flyt betingelsen(erne) til JOIN
klausul for at få det til at fungere efter hensigten. På denne måde er det kun rækker, der opfylder alle disse betingelser, der sammenføjes i første omgang (eller kolonner fra højre tabellen er udfyldt med NULL). Som du havde det, testes sammenføjede rækker for yderligere betingelser praktisk talt efter LEFT JOIN
og fjernet, hvis de ikke består, ligesom med en almindelig JOIN
.
count()
returnerer aldrig NULL til at begynde med. Det er en undtagelse blandt aggregerede funktioner i denne henseende. Derfor aldrig giver mening, selv med yderligere parametre. Manualen:COALESCE(COUNT(col))
Det skal bemærkes, at undtagen count
, returnerer disse funktioner en nulværdi, når ingen rækker er valgt.
Fed fremhævelse min. Se:
- Tæl antallet af attributter, der er NULL for en række
count()
skal være i en kolonne defineret NOT NULL
(som e.id
), eller hvor join-betingelsen garanterer NOT NULL
(e.organisation_id
, e.item_template_id
, eller e.used
) i eksemplet.
Siden used
er typen boolean
, udtrykket e.used = true
er støj, der brænder ned til kun e.used
.
Siden o.name
er ikke defineret UNIQUE NOT NULL
, vil du måske GROUP BY o.id
i stedet (id
er PK) - medmindre du agter det at folde rækker med samme navn (inklusive NULL).
Samle først, tilmeld dig senere
Hvis de fleste eller alle rækker af exam_items
tælles med i processen, er denne tilsvarende forespørgsel typisk betydeligt hurtigere/billigere:
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;
(Dette forudsætter, at du ikke ønsker at folde rækker med det samme navn som nævnt ovenfor - det typiske tilfælde.)
Nu kan vi bruge den hurtigere / enklere count(*)
i underforespørgslen, og vi behøver ingen GROUP BY
i den ydre SELECT
.
Se:
- Flere array_agg()-kald i en enkelt forespørgsel