Bancos de dados relacionais organizam dados em múltiplas tabelas para evitar redundância. JOIN é o mecanismo para reunir essas tabelas no momento da consulta.
id_cliente, nome, email
Dados do comprador
id_pedido, id_cliente, valor, data
id_cliente é FK → cliente
"Qual o nome do cliente que fez o pedido #42?"
A resposta está nas duas tabelas — precisamos de JOIN.
-- Sem JOIN: produto cartesiano (todas as combinações) SELECT * FROM cliente, pedido; -- Se cliente tem 100 linhas e pedido tem 500 → 50.000 linhas!
Produto cartesiano sem filtro é quase sempre um erro. Cada linha de uma tabela é combinada com cada linha da outra, gerando resultados sem sentido e potencialmente lentos.
A solução é sempre especificar a condição de junção — a coluna que relaciona as duas tabelas.
-- equijoin / theta join SELECT c.nome, p.id_pedido FROM cliente c, pedido p WHERE c.id_cliente = p.id_cliente;
Tabelas listadas no FROM separadas por vírgula; condição de junção no WHERE.
SELECT c.nome, p.id_pedido FROM cliente c, pedido p WHERE c.id_cliente = p.id_cliente;
SELECT c.nome, p.id_pedido FROM cliente c INNER JOIN pedido p ON c.id_cliente = p.id_cliente;
Por baixo dos panos: o banco gera o produto cartesiano e filtra com o WHERE — semanticamente idêntico ao INNER JOIN, mas menos legível.
INNER JOIN retorna apenas as linhas que têm correspondência em ambas as tabelas segundo a condição ON.
SELECT c.nome, p.id_pedido, p.valor FROM cliente c INNER JOIN pedido p ON c.id_cliente = p.id_cliente; -- Clientes sem nenhum pedido NÃO aparecem no resultado
A palavra INNER é opcional — JOIN sozinho já é INNER JOIN.
-- Alias de tabela (c, p) deixa o código mais limpo SELECT c.nome AS cliente, p.id_pedido, p.valor_total, p.status FROM cliente c JOIN pedido p ON c.id_cliente = p.id_cliente WHERE p.status = 'entregue' ORDER BY p.valor_total DESC LIMIT 10;
Use letras curtas (c, p) para evitar repetir o nome completo. Prefixe colunas ambíguas com o alias.
Filtre normalmente com WHERE depois do JOIN. A condição ON é apenas para definir a junção.
LEFT JOIN retorna todas as linhas da tabela à esquerda, mais as correspondências da direita. Onde não há correspondência, os campos da direita aparecem como NULL.
-- Todos os clientes, com ou sem pedido SELECT c.nome, p.id_pedido, p.valor_total FROM cliente c LEFT JOIN pedido p ON c.id_cliente = p.id_cliente; -- Clientes sem pedido: id_pedido = NULL, valor_total = NULL
Caso de uso típico: "Quero ver todos os clientes — incluindo os que ainda não compraram nada."
RIGHT JOIN é o espelho do LEFT JOIN: retorna todas as linhas da tabela à direita, mais as correspondências da esquerda.
-- Todos os pedidos, mesmo sem cliente cadastrado SELECT c.nome, p.id_pedido, p.valor_total FROM cliente c RIGHT JOIN pedido p ON c.id_cliente = p.id_cliente; -- Pedidos sem cliente: c.nome = NULL
RIGHT JOIN é raro: qualquer RIGHT JOIN pode ser reescrito como LEFT JOIN trocando a ordem das tabelas.
A RIGHT JOIN B é idêntico a B LEFT JOIN A. Use LEFT JOIN por consistência.
Retorna somente as linhas com correspondência em ambas as tabelas.
Use quando quer apenas dados completos.
Retorna todas da esquerda + correspondências da direita (NULL onde não há).
Use quando a tabela esquerda é a "principal".
Retorna todas da direita + correspondências da esquerda (NULL onde não há).
Equivalente a LEFT JOIN com tabelas invertidas.
-- Resumo rápido com a mesma base SELECT c.nome, p.id_pedido FROM cliente c JOIN pedido p ON c.id = p.id_cliente; -- INNER SELECT c.nome, p.id_pedido FROM cliente c LEFT JOIN pedido p ON c.id = p.id_cliente; -- LEFT SELECT c.nome, p.id_pedido FROM cliente c RIGHT JOIN pedido p ON c.id = p.id_cliente; -- RIGHT
A tabela esquerda é a que vem no FROM. A direita é a que vem após o JOIN.
FROM cliente c ← esquerda LEFT JOIN pedido p ← direita
Como escolher? Pergunte: "De qual tabela não posso perder nenhuma linha?" Essa vai na esquerda. A outra, que pode não ter correspondência, vai na direita.
Prefixe colunas com o alias da tabela (c.nome, p.valor) para evitar ambiguidade e facilitar a leitura.
Coloque a condição de junção no ON, filtros de negócio no WHERE. Misturá-los no WHERE pode mudar a semântica de LEFT JOINs.
Depois de um LEFT/RIGHT JOIN, colunas da tabela opcional podem ser NULL — trate isso nas queries e na aplicação.
Dado o esquema abaixo, escreva a query pedida.
id_cliente, nome, email
id_pedido, id_cliente, valor_total, status
Escreva uma query que retorne o nome de cada cliente, o total de pedidos que ele fez e a receita total (soma de valor_total). Mostre apenas clientes com 3 ou mais pedidos, ordenado por receita decrescente.
Esquema com quatro tabelas relacionadas:
cliente.id_cliente = pedido.id_cliente
pedido.id_pedido = item_pedido.id_pedido
item_pedido.id_produto = produto.id_produto
Siga as FKs do modelo ER — cada JOIN adiciona uma tabela ao caminho.
Escreva uma query que liste o nome do cliente, o nome do produto, a quantidade e o preço unitário de todos os itens comprados por Ana Lima.
Discuta com um colega. O objetivo é argumentar, não apenas responder.
Um sistema de biblioteca tem tabelas livro e emprestimo. Você quer listar todos os livros e, para cada um, mostrar quantas vezes foi emprestado (incluindo os nunca emprestados, com 0). Qual tipo de JOIN usar? Como a contagem deve ser feita para que livros nunca emprestados apareçam como 0 e não sejam excluídos?
Um colega escreveu: FROM pedido p LEFT JOIN cliente c ON … e outro escreveu FROM cliente c RIGHT JOIN pedido p ON …. As queries retornam o mesmo resultado? Em que situação uma pode ser preferível à outra?