sql >> Database teknologi >  >> RDS >> PostgreSQL

Forespørgsel med LEFT JOIN returnerer ikke rækker for tæller på 0

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 COALESCE(COUNT(col)) aldrig giver mening, selv med yderligere parametre. Manualen:

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


  1. Oprettelse af bruger med krypteret adgangskode i PostgreSQL

  2. ClusterControl 1.5 - Automatisk sikkerhedskopieringsbekræftelse, byg slave fra sikkerhedskopiering og skyintegration

  3. Ydeevne overraskelser og antagelser:STRING_SPLIT()

  4. SQLite Inner Join