Estou com uma dúvida básica de como JOIN
funciona em várias tabelas. Eu quero contar ocorrências de chave estrangeira em link1
&link2
CREATE TABLE main (
id SERIAL PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE link1 (
id SERIAL PRIMARY KEY,
main_id integer NOT NULL,
CONSTRAINT main_id_fk FOREIGN KEY (main_id) REFERENCES main (id)
);
-- link2 is similar to link1
Por que a consulta abaixo fornece um produto de contagens (em vez de soma) quando a contagem é diferente de zero em ambas as colunas.
SELECT main.id, COUNT(link1.main_id) + COUNT(link2.main_id)
FROM main
LEFT JOIN link1 ON main.id=link1.main_id
LEFT JOIN link2 ON main.id=link2.main_id
GROUP BY main.id
O que você vê é uma "junção cruzada de proxy". Agregar primeiro, depois juntar:
SQL Fiddle.
Não multiplique linhas com várias junções não qualificadas e depois
count(DISTINCT ...)
para corrigir o erro. Acontece que funciona neste caso, pois a contagem de DISTINCTlink1.id
/link2.id
coincide com o resultado desejado, mas é desnecessariamente caro e sujeito a erros.Explicação detalhada e algumas variantes de sintaxe nessas respostas relacionadas no SO:
Vou tentar responder eu mesmo. Considere um
LEFT JOIN
entremain
&link1
. A saída seriaAgora faça um
LEFT JOIN
da tabela acima comlink2
, a saída seria:Agora conte as ocorrências de
main_id
& some-as (agrupadas pormain.id
)Portanto, duas sucessivas
LEFT JOIN
estão acontecendo sequencialmente, e não em paralelo. A abordagem correta para obter a contagem seria realizar 2 consultas separadamente e adicionar os resultadosAtualizar Outra maneira de acordo com @ a1ex07 é