sql >> Database >  >> RDS >> PostgreSQL

Twee SQL LEFT JOINS produceren een onjuist resultaat

Joins worden van links naar rechts verwerkt (tenzij haakjes anders aangeven). Als je LEFT JOIN (of gewoon JOIN , soortgelijk effect) drie boodschappen voor één gebruiker krijg je 3 rijen (1 x 3 ). Als je dan lid wordt van 4 vismarkten voor dezelfde gebruiker, krijg je 12 (3 x 4 ) rijen, vermenigvuldigen de vorige telling in het resultaat, niet toevoegen ernaar toe, zoals je misschien had gehoopt.
Daardoor vermenigvuldigen de bezoeken voor zowel boodschappen als vismarkten.

Je kunt het als volgt laten werken:

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;

Om geaggregeerde waarden voor een of enkele gebruikers te krijgen, gecorreleerde subquery's zoals @Vince verstrekt zijn prima. Voor een hele tabel of grote delen ervan is het (veel) efficiënter om de n-tabellen samen te voegen en eenmaal aan het resultaat toe te voegen . Op deze manier hebben we ook geen andere GROUP BY nodig in de buitenste vraag.

grocery_visits en fishmarket_visits zijn NULL voor gebruikers zonder gerelateerde vermeldingen in de respectievelijke tabellen. Als je 0 nodig hebt gebruik in plaats daarvan (of een willekeurig nummer) COALESCE in de buitenste SELECT :

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


  1. Native wachtwoord gebruiken met MySQL 5.7

  2. Spotlight Cloud-ondersteuning voor Azure SQL DB-aankondiging (preview)

  3. SQL-tijdsverschil tussen twee datums resulteert in uu:mm:ss

  4. Geekbench 3 gebruiken om de prestaties van de databaseserver te evalueren