QA Learning / SQL

Módulo 4: Juntar tabelas

INNER JOIN, LEFT JOIN, 3+ tabelas

Teoria

  • INNER JOIN b ON a.x = b.y: só as linhas que casam nas duas tabelas.
  • LEFT JOIN: todas as linhas da tabela da esquerda, mesmo sem par na direita (as colunas da direita vêm NULL).
  • Padrão pra achar "quem não tem": LEFT JOIN ... WHERE b.id IS NULL.
  • Sempre qualifique colunas que existem nas duas tabelas: pedidos.id, clientes.id. Apelidos deixam mais curto: FROM pedidos p JOIN clientes c ON c.id = p.cliente_id.
  • Dá pra encadear 3+ JOIN na mesma query.

Olhar de QA: os dados reais moram espalhados em várias tabelas. JOIN é o que reconstrói "o pedido inteiro" pra você conferir.

Exemplos de aplicação

Um exemplo montado pra cada item da teoria acima. Não precisa rodar: é pra ver a cara do recurso e entender cada pedaço. Os valores são ilustrativos.

INNER JOIN

SELECT pedidos.id,
       pedidos.valor_total,
       clientes.nome AS cliente
FROM pedidos
INNER JOIN clientes ON clientes.id = pedidos.cliente_id;

O pedido guarda só o cliente_id. O ON clientes.id = pedidos.cliente_id casa cada pedido com a linha do cliente que tem aquele id, e aí dá pra mostrar o nome junto. INNER: pedido sem cliente correspondente fica de fora.

LEFT JOIN

SELECT clientes.nome,
       pedidos.id AS pedido_id
FROM clientes
LEFT JOIN pedidos ON pedidos.cliente_id = clientes.id;

LEFT JOIN mantém todos os clientes, com pedido ou sem. Quem tem pedido aparece uma vez por pedido; quem não tem aparece uma vez, com pedido_id vindo NULL, já que não há linha de pedido pra preencher.

Achar "quem não tem"

SELECT clientes.id, clientes.nome
FROM clientes
LEFT JOIN pedidos ON pedidos.cliente_id = clientes.id
WHERE pedidos.id IS NULL;

O LEFT JOIN traz o cliente mesmo sem pedido (colunas de pedidos em NULL); o WHERE pedidos.id IS NULL mantém só essas linhas. Resultado: clientes que nunca compraram.

Qualificar colunas + apelidos

SELECT p.id,
       p.data_pedido,
       c.nome AS cliente,
       c.estado
FROM pedidos AS p
JOIN clientes AS c ON c.id = p.cliente_id
WHERE c.estado = 'SP';

id existe nas duas tabelas; escrever p.id / c.id evita ambiguidade. O apelido (pedidos AS p) encurta o resto. JOIN sozinho já é INNER JOIN.

Encadear 3+ JOIN

SELECT p.id AS pedido,
       c.nome AS cliente,
       pr.nome AS produto,
       ip.quantidade
FROM pedidos AS p
JOIN clientes AS c      ON c.id = p.cliente_id
JOIN itens_pedido AS ip ON ip.pedido_id = p.id
JOIN produtos AS pr     ON pr.id = ip.produto_id;

Cada JOIN liga mais uma tabela pela chave certa: pedido→cliente, pedido→itens, item→produto. Assim você remonta a compra inteira (quem comprou, o quê, quantas unidades) numa linha por item.

Pegadinhas deste módulo

Os erros que quase todo mundo comete aqui. Ler agora poupa meia hora de confusão depois, e alguns deles são a causa de relatório errado em projeto real.

  • A armadilha clássica: filtrar a tabela da direita no WHERE transforma o LEFT JOIN num INNER JOIN, em silêncio.
    -- ERRADO: vira INNER JOIN e perde os clientes sem pedido
    SELECT c.nome, p.id
    FROM clientes c
    LEFT JOIN pedidos p ON p.cliente_id = c.id
    WHERE p.status = 'entregue';
    
    -- CERTO: a condição vai no ON
    SELECT c.nome, p.id
    FROM clientes c
    LEFT JOIN pedidos p ON p.cliente_id = c.id AND p.status = 'entregue';
    Por quê: o LEFT JOIN preenche com NULL quem não tem par, e o WHERE logo em seguida descarta essas linhas, porque NULL = 'entregue' não é verdadeiro. O resultado parece certo e está faltando gente. Regra: condição sobre a tabela da direita vai no ON; a única exceção é WHERE x IS NULL, que é justamente como se procura "quem não tem".
  • JOIN sem ON multiplica tudo. Esquecer a condição gera o produto cartesiano: 200 pedidos × 60 clientes = 12 000 linhas. Se o resultado veio absurdamente grande, é a primeira coisa a conferir.
  • JOIN com relação um-para-muitos duplica as linhas da esquerda. Juntar pedidos com itens_pedido repete o pedido uma vez por item. Aí SUM(p.valor_total) soma o mesmo pedido várias vezes e infla o total. É o erro de número mais difícil de perceber, porque o resultado parece plausível.
  • Sempre qualifique a coluna quando o nome existe nas duas tabelas. id sozinho num JOIN de pedidos com clientes é ambíguo: o banco reclama, ou pior, escolhe um.
  • Confira a contagem antes e depois do JOIN. Se pedidos tem 200 linhas e o seu JOIN devolveu 512, houve duplicação. Esse hábito de dois segundos evita relatório errado.

Prática

Rode com o botão ou Ctrl+Enter.

carregando banco…

Query livre

Terminou este módulo? Marque: o ✓ aparece no índice da trilha e a barra de progresso anda no começo do site. Fica salvo só no seu navegador.