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

Due SQL LEFT JOINS producono un risultato errato

I join vengono elaborati da sinistra a destra (a meno che le parentesi non indichino diversamente). Se LEFT JOIN (o semplicemente JOIN , effetto simile) tre generi alimentari a un utente ottieni 3 righe (1 x 3 ). Se poi ti unisci a 4 mercati ittici per lo stesso utente, ne ricevi 12 (3 x 4 ) righe, moltiplicando il conteggio precedente nel risultato, non aggiungendo ad esso, come forse avevi sperato.
Moltiplicando così le visite per generi alimentari e pescherie allo stesso modo.

Puoi farlo funzionare in questo modo:

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;

Per ottenere valori aggregati per uno o pochi utenti, sottoquery correlate come @Vince fornito vanno bene. Per un'intera tabella o parti principali di essa, è (molto) più efficiente aggregare le n-tabelle e unirle al risultato una volta . In questo modo, non abbiamo nemmeno bisogno di un altro GROUP BY nella query esterna.

grocery_visits e fishmarket_visits sono NULL per gli utenti senza voci correlate nelle rispettive tabelle. Se hai bisogno di 0 invece (o qualsiasi numero arbitrario), usa COALESCE nel SELECT esterno :

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