Cenários Práticos de SQL JOIN
Lição 5.8 · Tempo de leitura: ~8 min · Tarefas para praticar ↓
Esta lição reúne cenários práticos de SQL JOIN: juntar várias tabelas seguindo as relações do esquema, agregar dados juntados, encontrar dados em falta e evitar os dois erros de junção mais comuns: totais inflados e junções externas que perdem as suas linhas.
Você já conhece os tipos de junção; agora a tarefa é aplicá-los a perguntas reais. A maioria das consultas de relatório segue os mesmos passos: encontrar as tabelas que têm os dados, ligá-las pelas chaves, filtrar e agregar.
Planejar o Caminho da Junção
Comece pela pergunta e encontre um caminho entre as tabelas no diagrama do banco de dados. "Receita por categoria de filme" precisa de category, depois film_category, inventory, rental e por fim payment:
SELECT c.name AS category,
COUNT(p.payment_id) AS payments,
SUM(p.amount) AS revenue
FROM category AS c
INNER JOIN film_category AS fc ON fc.category_id = c.category_id
INNER JOIN inventory AS i ON i.film_id = fc.film_id
INNER JOIN rental AS r ON r.inventory_id = i.inventory_id
INNER JOIN payment AS p ON p.rental_id = r.rental_id
GROUP BY c.name
ORDER BY revenue DESC;
Resultado: 16 categorias ordenadas pela receita; Sports e Sci-Fi estão no topo.
A própria tabela film não é necessária: film_category e inventory guardam film_id, então podem ser juntadas diretamente. Junte apenas as tabelas que têm dados ou que são necessárias para ligá-las.
Agregar Depois de uma Junção
O gasto total de cada cliente:
SELECT c.customer_id,
c.first_name,
c.last_name,
COUNT(*) AS payments,
SUM(p.amount) AS total_spent
FROM customer AS c
INNER JOIN payment AS p ON p.customer_id = c.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name
ORDER BY total_spent DESC
LIMIT 10;
Resultado: os 10 clientes que mais gastaram.
Agrupe pela chave (customer_id), não apenas pelo nome: dois clientes diferentes podem ter o mesmo nome.
A Armadilha da Multiplicação: Totais Inflados
Uma junção multiplica linhas: um cliente com 30 pagamentos e 30 aluguéis vira 900 linhas se as duas tabelas forem juntadas ao cliente ao mesmo tempo. Qualquer soma sobre esse resultado está errada.
-- Errado: os pagamentos são multiplicados pelos aluguéis
SELECT c.customer_id,
SUM(p.amount) AS total_spent
FROM customer AS c
INNER JOIN payment AS p ON p.customer_id = c.customer_id
INNER JOIN rental AS r ON r.customer_id = c.customer_id
WHERE c.customer_id = 1
GROUP BY c.customer_id;
Resultado: 3797,76 em vez dos 118,68 reais: cada um dos 32 pagamentos do cliente foi contado uma vez para cada um dos seus 32 aluguéis.
A regra: não junte duas tabelas "muitos" independentes à mesma linha numa só consulta. Aqui a tabela rental nem é necessária. Quando você precisar de totais de duas tabelas assim, agregue cada uma separadamente primeiro; você vai aprender como fazer isso com subconsultas e CTEs no Módulo 6.
Encontrar Dados em Falta
LEFT JOIN ... WHERE right_key IS NULL encontra linhas sem correspondência. Clientes que não alugaram nada desde 23 de agosto de 2005:
SELECT c.customer_id, c.first_name, c.last_name
FROM customer AS c
LEFT JOIN rental AS r ON r.customer_id = c.customer_id
AND r.rental_date >= '2005-08-23'
WHERE r.rental_id IS NULL
ORDER BY c.customer_id;
Resultado: os clientes sem aluguéis nos últimos dias dos dados.
Repare na condição de data: ela está no ON, porque limita quais aluguéis contam como correspondência. No WHERE, ela removeria todos os clientes sem correspondência e a consulta não devolveria nada.
WHERE ou ON em Junções Externas
O exemplo anterior mostra a regra geral para LEFT JOIN:
| Condição sobre | Onde colocar | Efeito |
|---|---|---|
| a tabela da direita, para limitar correspondências | ON | As linhas da esquerda ficam; só as correspondências são filtradas |
| a tabela da esquerda | WHERE | As linhas da esquerda são removidas do resultado |
a chave da tabela da direita IS NULL | WHERE | Mantém só as linhas sem correspondência (anti-join) |
Para INNER JOIN, ON e WHERE dão o mesmo resultado, por isso o lugar é uma questão de legibilidade.
Principais conclusões:
- Planeje o caminho da junção pelo esquema e junte apenas as tabelas necessárias.
- Agrupe pelas chaves, não apenas pelos nomes.
- Juntar duas tabelas "muitos" à mesma linha multiplica as linhas e infla somas e contagens.
LEFT JOIN ... WHERE key IS NULLencontra dados em falta.- Em junções externas, as condições sobre a tabela da direita vão no
ON.
Perguntas Frequentes
Como juntar mais de duas tabelas em SQL?
Adicione um JOIN ... ON ... para cada tabela, seguindo as chaves estrangeiras do esquema. Cada junção liga uma nova tabela às tabelas que já estão na consulta.
Por que o meu SUM devolve um número muito maior depois de um JOIN?
Porque a junção multiplicou as linhas: cada linha de uma tabela repetiu-se para cada linha correspondente de outra. Remova as tabelas desnecessárias, ou agregue cada tabela separadamente antes de juntar os resultados.
Um filtro deve ir no ON ou no WHERE?
Para INNER JOIN, tanto faz. Para LEFT JOIN, uma condição sobre a tabela da direita vai no ON; no WHERE, ela remove as linhas sem correspondência e transforma a junção externa numa interna.