sql >> Database >  >> RDS >> PostgreSQL

Query met LEFT JOIN retourneert geen rijen voor telling van 0

Repareer de LEFT JOIN

Dit zou moeten werken:

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;

Je had een LEFT [OUTER] JOIN maar de latere WHERE omstandigheden zorgden ervoor dat het zich gedroeg als een eenvoudige [INNER] JOIN .
Verplaats de voorwaarde(n) naar de JOIN clausule om het te laten werken zoals bedoeld. Op deze manier worden alleen rijen die aan al deze voorwaarden voldoen in eerste instantie samengevoegd (of kolommen van rechts tabel zijn gevuld met NULL). Zoals u het had, worden samengevoegde rijen virtueel na . getest op aanvullende voorwaarden de LEFT JOIN en verwijderd als ze niet slagen, net als bij een gewone JOIN .

count() geeft om te beginnen nooit NULL terug. Het is in dit opzicht een uitzondering onder geaggregeerde functies. Daarom COALESCE(COUNT(col)) nooit is logisch, zelfs met extra parameters. De handleiding:

Opgemerkt moet worden dat behalve voor count , retourneren deze functies een null-waarde als er geen rijen zijn geselecteerd.

Vetgedrukte nadruk van mij. Zie:

  • Tel het aantal attributen dat NULL is voor een rij

count() moet op een kolom staan ​​gedefinieerd NOT NULL (zoals e.id ), of waar de join-voorwaarde NOT NULL . garandeert (e.organisation_id , e.item_template_id , of e.used ) in het voorbeeld.

Sinds used is type boolean , de uitdrukking e.used = true is ruis die opbrandt tot slechts e.used .

Sinds o.name is niet gedefinieerd UNIQUE NOT NULL , wilt u misschien GROUP BY o.id in plaats daarvan (id de PK zijn) - tenzij u van plan bent om rijen met dezelfde naam te vouwen (inclusief NULL).

Eerst samenvoegen, later meedoen

Als de meeste of alle rijen van exam_items worden meegeteld, is deze equivalente zoekopdracht doorgaans aanzienlijk sneller / goedkoper:

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;

(Dit gaat ervan uit dat je geen rijen wilt vouwen met dezelfde naam zoals hierboven vermeld - het typische geval.)

Nu kunnen we de snellere / eenvoudigere count(*) . gebruiken in de subquery, en we hebben geen GROUP BY . nodig in de buitenste SELECT .

Zie:

  • Meerdere array_agg()-aanroepen in één query


  1. MAKEDATE() Voorbeelden – MySQL

  2. SEC_CASE_SENSITIVE_LOGON Verouderd in 12c

  3. PostgreSQL 9.6:parallelle sequentiële scan

  4. Drop vs Truncate in SQL