Consultas com JOIN
Intermediário • 75 minutos • Conceito fundamental
Aprenda a combinar dados de múltiplas tabelas usando JOIN, a ferramenta mais poderosa do SQL para trabalhar com dados relacionados.
Objetivos de Aprendizagem
- Entender o conceito e importância do JOIN
- Dominar os tipos de JOIN (INNER, LEFT, RIGHT, FULL)
- Escrever consultas que combinam múltiplas tabelas
- Usar aliases para simplificar consultas
- Aplicar JOINs em cenários práticos
O que é JOIN?
JOIN é um comando SQL que permite combinar dados de duas ou mais tabelas baseado em uma relação entre elas. É como "colar" informações relacionadas em uma única consulta.
Analogia:
Imagine que você tem duas listas: uma com nomes de pessoas e outra com seus telefones. O JOIN é como juntar essas listas para ver nome e telefone de cada pessoa em uma única tabela.
Por que usar JOIN?
❌ Sem JOIN (problemático):
-- Buscar cliente
SELECT * FROM clientes WHERE id = 1;
-- Buscar pedidos do cliente (separadamente)
SELECT * FROM pedidos WHERE cliente_id = 1;
- • Múltiplas consultas
- • Dados separados
- • Mais complexo de processar
✅ Com JOIN (eficiente):
-- Buscar cliente e pedidos juntos
SELECT c.nome, p.produto, p.data_pedido
FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id
WHERE c.id = 1;
- • Uma única consulta
- • Dados combinados
- • Mais eficiente
Estrutura Básica do JOIN
SELECT colunas
FROM tabela1
JOIN tabela2 ON tabela1.coluna = tabela2.coluna;
🔗 Componentes do JOIN:
- FROM: Tabela principal (esquerda)
- JOIN: Tabela a ser combinada (direita)
- ON: Condição de ligação entre as tabelas
- SELECT: Colunas que queremos ver
Tipos de JOIN
Existem diferentes tipos de JOIN, cada um com um comportamento específico para combinar dados.
INNER JOIN
Retorna apenas os registros que têm correspondência em ambas as tabelas.
Quando usar:
Quando você quer apenas dados que existem nas duas tabelas.
-- Buscar clientes que fizeram pedidos
SELECT c.nome, c.email, p.produto, p.data_pedido
FROM clientes c
INNER JOIN pedidos p ON c.id = p.cliente_id;
Resultado:
| nome | produto | data_pedido | |
|---|---|---|---|
| João Silva | joao@email.com | Notebook | 2024-01-15 |
| Maria Santos | maria@email.com | Mouse | 2024-01-16 |
Só aparecem clientes que fizeram pedidos
LEFT JOIN (LEFT OUTER JOIN)
Retorna todos os registros da tabela da esquerda, mesmo que não tenham correspondência na direita.
Quando usar:
Quando você quer todos os dados da primeira tabela, independente de ter correspondência.
-- Buscar todos os clientes, com ou sem pedidos
SELECT c.nome, c.email, p.produto, p.data_pedido
FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id;
Resultado:
| nome | produto | data_pedido | |
|---|---|---|---|
| João Silva | joao@email.com | Notebook | 2024-01-15 |
| Maria Santos | maria@email.com | Mouse | 2024-01-16 |
| Pedro Costa | pedro@email.com | NULL | NULL |
Todos os clientes aparecem, mesmo sem pedidos (NULL)
RIGHT JOIN (RIGHT OUTER JOIN)
Retorna todos os registros da tabela da direita, mesmo que não tenham correspondência na esquerda.
Quando usar:
Menos comum. Geralmente se usa LEFT JOIN invertendo as tabelas.
-- Buscar todos os pedidos, com ou sem cliente
SELECT c.nome, c.email, p.produto, p.data_pedido
FROM clientes c
RIGHT JOIN pedidos p ON c.id = p.cliente_id;
FULL JOIN (FULL OUTER JOIN)
Retorna todos os registros de ambas as tabelas, com ou sem correspondência.
Quando usar:
Quando você quer ver tudo de ambas as tabelas, independente de correspondência.
-- Buscar todos os clientes e todos os pedidos
SELECT c.nome, c.email, p.produto, p.data_pedido
FROM clientes c
FULL OUTER JOIN pedidos p ON c.id = p.cliente_id;
Aliases e Boas Práticas
Aliases são "apelidos" que damos às tabelas para simplificar a escrita e leitura das consultas.
Usando Aliases
❌ Sem aliases (verboso):
SELECT clientes.nome,
clientes.email,
pedidos.produto,
pedidos.data_pedido
FROM clientes
JOIN pedidos ON clientes.id = pedidos.cliente_id;
✅ Com aliases (limpo):
SELECT c.nome,
c.email,
p.produto,
p.data_pedido
FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id;
Aliases para Colunas
SELECT c.nome AS cliente_nome,
c.email AS cliente_email,
p.produto AS produto_comprado,
p.data_pedido AS data_compra
FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id;
💡 Vantagens dos aliases:
- • Código mais limpo e legível
- • Menos digitação
- • Nomes de colunas mais descritivos no resultado
- • Evita ambiguidade quando colunas têm o mesmo nome
Exemplos Práticos
Vamos ver exemplos práticos usando o sistema de e-commerce que criamos na aula anterior.
1. Produtos com suas Categorias
-- Listar produtos com nome da categoria
SELECT p.nome AS produto,
p.preco,
c.nome AS categoria
FROM produtos p
INNER JOIN categorias c ON p.categoria_id = c.id
ORDER BY c.nome, p.nome;
Resultado:
| produto | preco | categoria |
|---|---|---|
| Sofá | R$ 1.299,99 | Casa |
| Notebook | R$ 2.499,99 | Eletrônicos |
| Smartphone | R$ 899,99 | Eletrônicos |
2. Pedidos Completos com Detalhes
-- Relatório completo de pedidos
SELECT ped.id AS pedido_numero,
c.nome AS cliente,
c.email,
ped.data_pedido,
ped.status,
prod.nome AS produto,
ip.quantidade,
ip.preco_unitario,
(ip.quantidade * ip.preco_unitario) AS subtotal
FROM pedidos ped
INNER JOIN clientes c ON ped.cliente_id = c.id
INNER JOIN itens_pedido ip ON ped.id = ip.pedido_id
INNER JOIN produtos prod ON ip.produto_id = prod.id
ORDER BY ped.data_pedido DESC;
Nota: Este exemplo usa múltiplos JOINs para combinar 4 tabelas diferentes!
3. Clientes sem Pedidos
-- Encontrar clientes que nunca fizeram pedidos
SELECT c.nome,
c.email,
c.telefone
FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id
WHERE p.id IS NULL;
Dica: Usamos LEFT JOIN + WHERE IS NULL para encontrar registros sem correspondência.
4. Resumo de Vendas por Categoria
-- Vendas totais por categoria
SELECT cat.nome AS categoria,
COUNT(ip.id) AS total_itens_vendidos,
SUM(ip.quantidade * ip.preco_unitario) AS receita_total
FROM categorias cat
INNER JOIN produtos p ON cat.id = p.categoria_id
INNER JOIN itens_pedido ip ON p.id = ip.produto_id
GROUP BY cat.id, cat.nome
ORDER BY receita_total DESC;
Avançado: Combina JOIN com GROUP BY para criar relatórios agregados.
Exercício Prático
Vamos praticar JOINs!
Complete as consultas SQL abaixo:
1. Que tipo de JOIN usar para "todos os clientes, com ou sem pedidos"?
2. Complete a consulta para listar produtos com suas categorias:
SELECT p.nome, c.nome AS categoria
FROM produtos p
_______ _______ categorias c ON p.categoria_id = c.id;
3. Para encontrar produtos sem pedidos, usamos:
4. Complete os aliases na consulta:
SELECT __.nome, __.email, __.produto
FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id;
Erros Comuns
❌ Esquecer a condição ON
-- ERRO: Sem condição ON
SELECT * FROM clientes c
JOIN pedidos p; -- Vai gerar produto cartesiano!
Resultado: Cada cliente será combinado com TODOS os pedidos.
❌ Ambiguidade em nomes de colunas
-- ERRO: Coluna 'id' existe nas duas tabelas
SELECT id, nome FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id;
Solução: Sempre especificar a tabela: c.id ou p.id
❌ Usar INNER JOIN quando precisa de LEFT JOIN
-- ERRO: Só mostra clientes com pedidos
SELECT c.nome FROM clientes c
INNER JOIN pedidos p ON c.id = p.cliente_id;
-- CORRETO: Mostra todos os clientes
SELECT c.nome FROM clientes c
LEFT JOIN pedidos p ON c.id = p.cliente_id;
⚠️ Performance com muitos JOINs
Muitos JOINs podem deixar a consulta lenta. Use índices nas colunas de FK e teste a performance.
Resumo da Aula
- JOIN combina dados de múltiplas tabelas relacionadas
- INNER JOIN: apenas registros com correspondência
- LEFT JOIN: todos da esquerda + correspondências da direita
- Aliases tornam as consultas mais legíveis
- Sempre especificar a condição ON para evitar produto cartesiano