PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Dois SQL LEFT JOINS produzem resultado incorreto


As junções são processadas da esquerda para a direita (a menos que os parênteses indiquem o contrário). Se você LEFT JOIN (ou apenas JOIN , efeito semelhante) três mantimentos para um usuário, você obtém 3 linhas (1 x 3 ). Se você entrar em 4 peixarias para o mesmo usuário, receberá 12 (3 x 4 ) linhas, multiplicando a contagem anterior no resultado, não adicionando para ele, como você pode ter esperado.
Multiplicando assim as visitas para mantimentos e peixarias.

Você pode fazer funcionar assim:
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;

Para obter valores agregados para um ou poucos usuários, subconsultas correlacionadas como @Vince fornecidos estão bem. Para uma tabela inteira ou partes principais dela, é (muito) mais eficiente agregar as n-tabelas e juntar ao resultado uma vez . Dessa forma, também não precisamos de outro GROUP BY na consulta externa.

grocery_visits e fishmarket_visits são NULL para usuários sem entradas relacionadas nas respectivas tabelas. Se você precisar de 0 em vez disso (ou qualquer número arbitrário), use COALESCE no SELECT externo :
SELECT u.id
     , u.account_balance
     , COALESCE(g.grocery_visits   , 0) AS grocery_visits
     , COALESCE(f.fishmarket_visits, 0) AS fishmarket_visits
FROM   ...