Voltar para o conteúdo

Erros Comuns: quando seu JOIN duplica linhas e distorce a métrica

Como identificar, explicar e corrigir o erro de JOIN que multiplica linhas sem aviso e faz receita, pedidos e conversões parecerem maiores do que realmente são.

Raphael Carvalho · 04 de jun. de 2026 · 8 min de leitura

Resumo rápido

  • O JOIN problemático quase nunca falha na sintaxe; ele falha na granularidade entre as tabelas que você está combinando.
  • Quando uma chave encontra várias linhas do outro lado, a consulta pode inflar receita, pedidos, usuários ou conversões sem parecer quebrada.
  • Diagnóstico bom exige contar linhas antes e depois, validar cardinalidade e agregar na granularidade certa antes de juntar.

Um dos erros mais caros em SQL não é um SELECT com sintaxe quebrada. É uma query que roda sem reclamar, entrega um número bonito e está errada porque o JOIN multiplicou linhas no caminho.

Esse tipo de erro é traiçoeiro porque parece análise pronta. O dashboard abre, a tabela soma, a reunião anda. Só depois alguém percebe que a receita ficou maior do que a real, que o volume de pedidos dobrou ou que a taxa de conversão perdeu o sentido.

Na prática, o problema quase nunca está no comando JOIN em si. Está na granularidade que você esqueceu de validar antes de cruzar as tabelas.

O que realmente acontece quando um JOIN duplica linhas

Vamos supor um cenário comum:

  • uma tabela de pedidos;
  • uma tabela de itens_pedido;
  • uma tabela de clientes.

Se você quer calcular receita por cliente e junta clientes com pedidos e depois com itens_pedido, precisa saber o que cada linha representa em cada etapa.

  • clientes: uma linha por cliente;
  • pedidos: uma linha por pedido;
  • itens_pedido: várias linhas por pedido.

Se você soma o valor de pedidos.total_pedido depois de entrar em itens_pedido, esse total pode ser repetido uma vez para cada item do pedido. O banco não está errado. Ele só está devolvendo todas as combinações válidas segundo a sua regra de junção.

O erro é analítico: a pergunta exigia uma granularidade, mas a query foi montada em outra.

O sinal clássico: a métrica cresce sem explicação de negócio

O primeiro alerta costuma ser este: depois do JOIN, o número cresce demais e ninguém consegue explicar por quê.

Exemplos típicos:

  • receita maior do que o faturamento conhecido;
  • mais pedidos do que IDs únicos de pedido;
  • mais leads convertidos do que registros no CRM;
  • mais usuários do que a própria base de usuários.

Quando isso acontece, muita gente corre para DISTINCT, troca agregação ou mexe em filtro. Às vezes até “resolve” o número. Mas, sem entender a causa, você só troca um erro visível por um erro silencioso.

O erro de raciocínio por trás do problema

O padrão costuma ser um destes:

  1. A pessoa assume que a chave do JOIN é única dos dois lados, mas ela não é.
  2. A pessoa junta uma tabela detalhada antes de agregar.
  3. A pessoa soma uma métrica já consolidada depois de entrar em uma tabela mais granular.
  4. A pessoa não valida o que uma linha representa em cada tabela.

Em todas essas situações, a pergunta correta não é “qual JOIN usar?”. A pergunta correta é “qual deve ser a unidade final da análise?”.

Se a resposta é “uma linha por pedido”, todo o resto da query precisa respeitar isso.

Como diagnosticar sem perder tempo

Quando eu suspeito de duplicidade em JOIN, sigo uma sequência simples.

1. Contar linhas antes e depois do JOIN

Comece pelo básico:

SELECT COUNT(*) AS linhas_pedidos
FROM pedidos;

Depois:

SELECT COUNT(*) AS linhas_pos_join
FROM pedidos p
LEFT JOIN itens_pedido i
  ON p.id_pedido = i.id_pedido;

Se o volume sobe de forma relevante, isso não prova erro sozinho, mas confirma que houve multiplicação de linhas.

2. Testar a cardinalidade da chave

Agora verifique se a chave do lado direito aparece mais de uma vez:

SELECT
  id_pedido,
  COUNT(*) AS qtd_linhas
FROM itens_pedido
GROUP BY id_pedido
HAVING COUNT(*) > 1;

Se esse resultado existir, você já sabe que um pedido pode virar várias linhas depois do JOIN.

3. Comparar contagem distinta com contagem total

SELECT
  COUNT(*) AS linhas_total,
  COUNT(DISTINCT p.id_pedido) AS pedidos_distintos
FROM pedidos p
LEFT JOIN itens_pedido i
  ON p.id_pedido = i.id_pedido;

Quando linhas_total é maior do que pedidos_distintos, sua tabela final não está mais na granularidade de pedido.

4. Inspecionar um caso real

Escolha um ID específico e abra o detalhe:

SELECT
  p.id_pedido,
  p.total_pedido,
  i.id_item,
  i.valor_item
FROM pedidos p
LEFT JOIN itens_pedido i
  ON p.id_pedido = i.id_pedido
WHERE p.id_pedido = 12345;

Esse passo é importante porque transforma um problema abstrato em algo visível. Você vê a repetição acontecendo.

O erro mais comum de correção: esconder com DISTINCT

DISTINCT tem utilidade, mas vira muleta fácil.

Se você faz isto:

SELECT DISTINCT
  p.id_pedido,
  p.total_pedido
FROM pedidos p
LEFT JOIN itens_pedido i
  ON p.id_pedido = i.id_pedido;

talvez a lista de pedidos volte a parecer correta. Só que isso não garante que a lógica da análise esteja certa quando entram outras colunas, outras métricas ou novas tabelas no mesmo fluxo.

O ponto é simples: DISTINCT remove sintomas. Nem sempre corrige a modelagem da consulta.

O jeito mais seguro de corrigir

Na maioria dos casos, a correção passa por agregar antes de juntar.

Se você precisa de informação de itens_pedido, primeiro reduza essa tabela para a granularidade que a análise exige:

WITH itens_por_pedido AS (
  SELECT
    id_pedido,
    COUNT(*) AS qtd_itens,
    SUM(valor_item) AS valor_itens
  FROM itens_pedido
  GROUP BY id_pedido
)
SELECT
  p.id_pedido,
  p.id_cliente,
  p.total_pedido,
  i.qtd_itens,
  i.valor_itens
FROM pedidos p
LEFT JOIN itens_por_pedido i
  ON p.id_pedido = i.id_pedido;

Agora o JOIN volta a conectar “uma linha por pedido” com “uma linha por pedido”. A chance de distorção cai muito.

O que validar antes de confiar na query final

Antes de publicar resultado, levar para dashboard ou usar em decisão, valide quatro pontos:

  • o que cada linha representa na tabela final;
  • se a chave de junção é única ou repetida em cada lado;
  • se alguma métrica consolidada está sendo somada depois de entrar em detalhe;
  • se o total final fecha com uma fonte de controle mais simples.

Esse último ponto é subestimado. Se sua query calcula receita por cliente, confira o total agregado contra uma consulta curta de faturamento. Se não fecha, o erro pode estar no JOIN, não no negócio.

Por que esse erro aparece tanto em times bons

Porque ele nasce em cenário real.

No mundo do trabalho, você raramente analisa uma tabela perfeita e isolada. Você cruza base de pedidos com itens, campanhas com sessões, leads com CRM, contratos com eventos, usuários com pagamentos. Quase sempre há múltiplas granularidades convivendo.

Quem trabalha bem com SQL não é quem sabe só escrever LEFT JOIN. É quem olha para uma tabela e pergunta: “o que uma linha representa aqui?”.

Essa pergunta evita boa parte das métricas falsas que parecem plausíveis.

Resumo direto

Quando um JOIN duplica linhas, o banco não está “inventando” dado. Ele está obedecendo a relação entre tabelas que você mandou usar.

O erro aparece quando a análise ignora cardinalidade, granularidade e ordem de agregação. Por isso, antes de corrigir com DISTINCT, conte linhas, valide chaves e agregue na unidade certa.

É isso que separa uma query que roda de uma query que você realmente pode defender.

Se quiser reforçar essa base, estes conteúdos ajudam na sequência:

SQL para criação de tabelas e ETL

Aprenda a criar estruturas, manipular dados e montar fluxos simples de ETL em SQL.

Avançar em SQL operacional

Perguntas frequentes

Todo JOIN que aumenta a quantidade de linhas está errado?

Não. Em tabelas transacionais, é normal que uma entidade tenha várias linhas relacionadas. O erro aparece quando essa multiplicação não era esperada para a pergunta que você quer responder.

DISTINCT resolve esse problema?

Só em alguns casos e, muitas vezes, esconde o erro. Se a granularidade estiver errada, usar DISTINCT sem entender a causa pode apagar sinais importantes e ainda deixar a métrica incorreta.

Qual é o primeiro teste que devo rodar?

Compare a contagem da tabela base com a contagem depois do JOIN e investigue a chave com GROUP BY e HAVING COUNT(*) > 1. Isso já mostra se existe multiplicação inesperada.

Curso em português para brasileiros

SQL do Zero ao Avançado

A plataforma interativa de SQL feita para analistas. Pare de depender da fila de engenharia de dados.

Conheça o curso

Advertisement: SQL do Zero ao Avançado

Sobre o autor

Raphael Carvalho

Founder & Principal Consultant

Compartilhar Twitter LinkedIn

Leituras recomendadas