Korrigieren Sie den LEFT JOIN
Das sollte funktionieren:
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;
Sie hatten einen LEFT [OUTER] JOIN
aber das spätere WHERE
Bedingungen ließen es sich wie ein einfacher [INNER] JOIN
verhalten .
Verschieben Sie die Bedingung(en) in den JOIN
Klausel, damit es wie beabsichtigt funktioniert. Auf diese Weise werden überhaupt nur Zeilen verbunden, die alle diese Bedingungen erfüllen (oder Spalten von rechts Tabelle sind mit NULL gefüllt). Wie Sie es hatten, werden verbundene Zeilen praktisch nach auf zusätzliche Bedingungen getestet der LEFT JOIN
und entfernt, wenn sie nicht bestehen, genau wie bei einem einfachen JOIN
.
count()
gibt von vornherein nie NULL zurück. Diesbezüglich ist es eine Ausnahme unter den Aggregatfunktionen. Daher nie sinnvoll, auch mit zusätzlichen Parametern. Das Handbuch:COALESCE(COUNT(col))
Es sollte beachtet werden, dass mit Ausnahme von count
, geben diese Funktionen einen Nullwert zurück, wenn keine Zeilen ausgewählt sind.
Fette Hervorhebung von mir. Siehe:
- Zählen Sie die Anzahl der Attribute, die für eine Zeile NULL sind
count()
muss auf einer Spalte definiert sein NOT NULL
(wie e.id
) oder wo die Join-Bedingung NOT NULL
garantiert (e.organisation_id
, e.item_template_id
, oder e.used
) im Beispiel.
Seit used
ist vom Typ boolean
, der Ausdruck e.used = true
ist Rauschen, das sich auf nur noch e.used
niederbrennt .
Seit o.name
ist nicht definiert UNIQUE NOT NULL
, möchten Sie vielleicht GROUP BY o.id
stattdessen (id
der PK ist) - es sei denn, Sie beabsichtigen um Zeilen mit demselben Namen (einschließlich NULL) zu falten.
Erst aggregieren, später beitreten
Wenn die meisten oder alle Zeilen von exam_items
dabei gezählt werden, ist diese äquivalente Abfrage typischerweise deutlich schneller / günstiger:
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;
(Dies setzt voraus, dass Sie Zeilen mit demselben Namen nicht wie oben erwähnt falten möchten - der typische Fall.)
Jetzt können wir das schnellere / einfachere count(*)
verwenden in der Unterabfrage, und wir brauchen kein GROUP BY
im äußeren SELECT
.
Siehe:
- Mehrere array_agg()-Aufrufe in einer einzigen Abfrage