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êmNULL).- 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+
JOINna 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
WHEREtransforma oLEFT JOINnumINNER JOIN, em silêncio.
Por quê: o-- 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';LEFT JOINpreenche comNULLquem não tem par, e oWHERElogo em seguida descarta essas linhas, porqueNULL = 'entregue'não é verdadeiro. O resultado parece certo e está faltando gente. Regra: condição sobre a tabela da direita vai noON; a única exceção éWHERE x IS NULL, que é justamente como se procura "quem não tem". JOINsemONmultiplica 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.JOINcom relação um-para-muitos duplica as linhas da esquerda. Juntarpedidoscomitens_pedidorepete 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.
idsozinho numJOINdepedidoscomclientesé ambíguo: o banco reclama, ou pior, escolhe um. - Confira a contagem antes e depois do
JOIN. Sepedidostem 200 linhas e o seuJOINdevolveu 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…