PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Zwei SQL LEFT JOINS erzeugen ein falsches Ergebnis

Joins werden von links nach rechts verarbeitet (es sei denn, Klammern schreiben etwas anderes vor). Wenn Sie LEFT JOIN (oder einfach JOIN , ähnlicher Effekt) drei Lebensmittel für einen Benutzer erhalten Sie 3 Zeilen (1 x 3 ). Wenn Sie dann 4 Fischmärkten für denselben Benutzer beitreten, erhalten Sie 12 (3 x 4 ) Zeilen, Multiplizieren die vorherige Zählung im Ergebnis, nicht Hinzufügen dazu, wie Sie es sich vielleicht erhofft haben.
Dadurch vervielfachen sich die Besuche für Lebensmittel und Fischmärkte gleichermaßen.

Sie können es so machen:

SELECT u.id
     , u.account_balance
     , g.grocery_visits
     , f.fishmarket_visits
FROM   users u
LEFT   JOIN (
   SELECT user_id, count(*) AS grocery_visits
   FROM   grocery
   GROUP  BY user_id
   ) g ON g.user_id = u.id
LEFT   JOIN (
   SELECT user_id, count(*) AS fishmarket_visits
   FROM   fishmarket
   GROUP  BY user_id
   ) f ON f.user_id = u.id
ORDER  BY u.id;

Um aggregierte Werte für einen oder wenige Benutzer zu erhalten, korrelieren Sie Unterabfragen wie @Vince vorausgesetzt, sind in Ordnung. Für eine ganze Tabelle oder größere Teile davon ist es (viel) effizienter, die n-Tabellen zu aggregieren und einmal mit dem Ergebnis zu verknüpfen . Auf diese Weise brauchen wir auch kein weiteres GROUP BY in der äußeren Abfrage.

grocery_visits und fishmarket_visits sind NULL für Benutzer ohne entsprechende Einträge in den jeweiligen Tabellen. Wenn Sie 0 benötigen Verwenden Sie stattdessen (oder eine beliebige Zahl) COALESCE im äußeren SELECT :

SELECT u.id
     , u.account_balance
     , COALESCE(g.grocery_visits   , 0) AS grocery_visits
     , COALESCE(f.fishmarket_visits, 0) AS fishmarket_visits
FROM   ...