sql >> Databáze >  >> RDS >> PostgreSQL

Dotaz s LEFT JOIN nevrací řádky pro počet 0

Opravte LEFT JOIN

Mělo by to fungovat:

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;

Měli jste LEFT [OUTER] JOIN ale pozdější WHERE podmínky způsobily, že to funguje jako prosté [INNER] JOIN .
Přesuňte podmínky do JOIN klauzule, aby to fungovalo tak, jak bylo zamýšleno. Tímto způsobem se na prvním místě spojí pouze řádky, které splňují všechny tyto podmínky (nebo sloupce z zprava tabulka je vyplněna NULL). Jak jste to měli vy, spojené řádky jsou prakticky po testovány na další podmínky LEFT JOIN a odstraněny, pokud neprojdou, stejně jako u obyčejného JOIN .

count() pro začátek nikdy nevrátí NULL. V tomto ohledu je to výjimka mezi agregovanými funkcemi. Proto COALESCE(COUNT(col)) nikdy dává smysl i s dalšími parametry. Manuál:

Je třeba poznamenat, že s výjimkou count , tyto funkce vrátí hodnotu null, pokud nejsou vybrány žádné řádky.

Odvážný důraz můj. Viz:

  • Spočítejte počet atributů, které mají hodnotu NULL na řádku

count() musí být ve sloupci definovaném NOT NULL (jako e.id ), nebo kde podmínka spojení zaručuje NOT NULL (e.organisation_id , e.item_template_id , nebo e.used ) v příkladu.

Od used je typu boolean , výraz e.used = true je šum, který se spálí na pouhé e.used .

Od o.name není definováno UNIQUE NOT NULL , možná budete chtít GROUP BY o.id místo toho (id být PK) – pokud to nemáte v úmyslu pro skládání řádků se stejným názvem (včetně NULL).

Nejprve agregujte, připojte se později

Pokud většina nebo všechny řádky exam_items se v procesu započítávají, tento ekvivalentní dotaz je obvykle podstatně rychlejší / levnější:

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;

(Předpokládáme, že nechcete skládat řádky se stejným názvem, jak je uvedeno výše – typický případ.)

Nyní můžeme použít rychlejší / jednodušší count(*) v poddotazu a nepotřebujeme žádný GROUP BY ve vnějším SELECT .

Viz:

  • Více volání array_agg() v jednom dotazu


  1. Zdarma webhosting s podporou PHP

  2. Použití Dapper s uloženými procedurami Oracle, které vracejí kurzory

  3. Nahrazení řetězce jiným řetězcem v SQL Server (T-SQL)

  4. Jak vrátit výsledek SELECT uvnitř funkce v PostgreSQL?