sql >> Databasteknik >  >> RDS >> PostgreSQL

Fråga med LEFT JOIN returnerar inte rader för antalet 0

Åtgärda LEFT JOIN

Detta borde fungera:

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 hade en LEFT [OUTER] JOIN men den senare WHERE villkoren gjorde att den fungerade som en vanlig [INNER] JOIN .
Flytta villkoren/villkoren till JOIN klausul för att få det att fungera som avsett. På så sätt sammanfogas endast rader som uppfyller alla dessa villkor i första hand (eller kolumner från höger tabellen är fylld med NULL). Som du hade det, testas sammanfogade rader för ytterligare förhållanden praktiskt taget efter LEFT JOIN och tas bort om de inte går igenom, precis som med en vanlig JOIN .

count() returnerar aldrig NULL till att börja med. Det är ett undantag bland aggregerade funktioner i detta avseende. Därför COALESCE(COUNT(col)) aldrig vettigt, även med ytterligare parametrar. Manualen:

Det bör noteras att förutom count , returnerar dessa funktioner ett nollvärde när inga rader är markerade.

Djärv betoning min. Se:

  • Räkna antalet attribut som är NULL för en rad

count() måste vara i en kolumn definierad NOT NULL (som e.id ), eller där anslutningsvillkoret garanterar NOT NULL (e.organisation_id , e.item_template_id , eller e.used ) i exemplet.

Sedan used är typ boolean , uttrycket e.used = true är brus som brinner ner till bara e.used .

Sedan o.name är inte definierad UNIQUE NOT NULL , kanske du vill GROUP BY o.id istället (id är PK) - om du inte avser för att vika rader med samma namn (inklusive NULL).

Aggregera först, gå med senare

Om de flesta eller alla rader med exam_items räknas i processen, är denna motsvarande fråga vanligtvis betydligt snabbare/billigare:

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;

(Detta förutsätter att du inte vill vika rader med samma namn som nämnts ovan - det typiska fallet.)

Nu kan vi använda den snabbare/enklare count(*) i underfrågan, och vi behöver ingen GROUP BY i den yttre SELECT .

Se:

  • Flera array_agg()-anrop i en enda fråga


  1. SQL Server Error 213:Kolumnnamn eller antal angivna värden matchar inte tabelldefinitionen.

  2. Ny funktion för BYOC – Pausa och återuppta kluster

  3. Bästa metoder för skalning av databaser:Del 1

  4. Uppdatera rader i en tabell med data från en annan tabell baserat på att en kolumn i varje är lika