A relação determina o resultado
INNER JOIN mantém combinações que satisfazem a condição. LEFT JOIN mantém também linhas da esquerda sem correspondência, preenchendo as colunas da direita com NULL. Uma relação de um para muitos pode produzir várias linhas por entidade; isso não é, por si só, um erro.
Filtros que alteram o significado
Num LEFT JOIN, uma condição de WHERE que exige um valor da tabela direita pode eliminar as linhas sem correspondência. Decide se a condição pertence à correspondência ON ou ao filtro final. Antes de contar ou somar, verifica a granularidade de cada linha.
Aplicação guiada no trabalho
Desenha uma amostra com três equipas: uma com incidentes abertos, outra apenas com fechados e outra sem incidentes. O painel precisa das três. Coloca o filtro de estado no ON do LEFT JOIN e conta i.id, assumindo que é uma chave não nula. Assim, a ausência de correspondência dá zero incidentes. Colocar o filtro no WHERE exclui linhas preservadas; acrescentar OR i.id IS NULL também não recupera a equipa cujos incidentes fechados já corresponderam no JOIN. Para mostrar apenas clientes que têm pedidos, sem detalhes dos pedidos, considera EXISTS. Antes de somar montantes, descreve a granularidade: encomenda, linha de encomenda ou cliente. Uma junção correta pode multiplicar linhas legitimamente, mas o total deve continuar a representar a entidade pretendida.
SELECT teams.name, COUNT(incidents.id) AS open_count
FROM teams
LEFT JOIN incidents ON incidents.team_id = teams.id
AND incidents.resolved_at IS NULL
GROUP BY teams.id, teams.name;Para mostrar equipas sem incidentes abertos, preserva as equipas da esquerda e coloca o filtro de incidentes na condição de correspondência.
Armadilhas comuns
Mover filtros sem testar equipas sem correspondência; confundir linhas com entidades.
Tópicos relacionados: Contar e agrupar com cuidado · Alterações que preservam regras
Valida cardinalidade e condições antes de interpretar totais de um JOIN.
Referência: PostgreSQL 18: Table expressions · PostgreSQL 18 reference semantics; DR SQL 2026.4; synthetic plan metrics and portable SQLite 3.51.2 examples