SQLJOININNER JOINtutorial

O que é INNER JOIN no SQL? Juntar tabelas para iniciantes

INNER JOIN combina linhas de duas tabelas por uma chave compartilhada. O JOIN mais simples e mais comum. Cobrimos a sintaxe, a cláusula ON, as junções de várias tabelas, os erros comuns e três exercícios práticos.

7 min de leituraSQL · JOIN · INNER JOIN · tutorial · beginner

INNER JOIN (ou apenas JOIN) é o comando do SQL para combinar duas tabelas por uma chave compartilhada. O tipo de JOIN mais simples e mais comum — com bancos de dados relacionais você não vai longe sem ele.

Uma analogia rápida. Você tem duas tabelas:

  • users — usuários (id, name)
  • orders — pedidos (id, user_id, amount)

Em orders não há nome do comprador — apenas user_id. Para obter pares de "nome do comprador + valor do pedido", você precisa colar essas tabelas de volta por uma chave comum — users.id corresponde a orders.user_id. Essa colagem é o INNER JOIN.

Por que JOIN importa

Um banco de dados normal distribui os dados entre tabelas para evitar a duplicação. O nome do usuário vive apenas em users; orders referencia o usuário através de user_id. Isso se chama normalização.

Quando você precisa mostrar "nome + pedido", precisa montar os dados de volta — é para isso que serve o JOIN. É um dos temas mais importantes do SQL — sem JOIN você não consegue escrever nenhuma consulta do mundo real.

Sintaxe básica

SELECT columns
FROM table_A
INNER JOIN table_B
  ON table_A.key = table_B.key;

A palavra INNER é opcional — JOIN sem prefixo significa INNER JOIN. A maioria do código escreve apenas JOIN.

Exemplo: uma loja

Tabela users:

idnameemail
1Annaanna@example.com
2Borisbob@example.com
3Veravera@example.com
4Grishagrisha@example.com

Tabela orders:

iduser_idamountcreated_at
1015002024-03-01
11115002024-03-05
1222002024-03-07
13530002024-03-10

Consulta — juntar e mostrar o nome do comprador com o valor:

SELECT users.name, orders.amount, orders.created_at
FROM users
INNER JOIN orders
  ON users.id = orders.user_id;

Resultado:

nameamountcreated_at
Anna5002024-03-01
Anna15002024-03-05
Boris2002024-03-07

O que aconteceu:

  • Cada linha de users foi pareada com cada linha de orders onde users.id = orders.user_id.
  • Anna tem dois pedidos → duas linhas no resultado, com o nome duplicado.
  • Boris tem um pedido → uma linha.
  • Vera e Grisha não estão lá — eles não têm pedidos. Essa é a característica do INNER JOIN: apenas pares com correspondência em ambas as tabelas.
  • O pedido #13 não está láuser_id = 5 não existe em users. Às vezes acontece, por exemplo, o usuário foi excluído mas o pedido permaneceu.

Se você também quiser os usuários sem pedidos, isso é LEFT JOIN (artigo separado).

Aliases — nomes curtos de tabela

Escrever users.name, orders.amount toda vez é longo. O código do mundo real usa aliases:

SELECT u.name, o.amount, o.created_at
FROM users u
INNER JOIN orders o
  ON u.id = o.user_id;

users u significa "dê à tabela users o alias u". Não muda a lógica — apenas é mais curto. Em consultas grandes com três a cinco tabelas, as consultas sem aliases são ilegíveis.

Observação: os aliases se tornam obrigatórios se ambas as tabelas têm uma coluna com o mesmo nome. Caso contrário o banco de dados não consegue saber a qual id você se refere.

Juntar três ou mais tabelas

Os JOINs se encadeiam: A JOIN B JOIN C. Adicione uma tabela products:

idnameprice
100Bosch kettle49
101iPhone 15999
102Book "Clean Code"22

E estenda orders com product_id:

iduser_idproduct_idamount
10110049
11110222
12210049

Consulta — quem comprou o quê:

SELECT u.name AS buyer, p.name AS product, o.amount
FROM users u
INNER JOIN orders o   ON u.id = o.user_id
INNER JOIN products p ON p.id = o.product_id;

Resultado:

buyerproductamount
AnnaBosch kettle49
AnnaBook "Clean Code"22
BorisBosch kettle49

Como funciona:

  1. O banco de dados primeiro junta users e orders por user_id.
  2. Depois o resultado é juntado com products por product_id.
  3. A saída mantém apenas as linhas onde ambas as junções corresponderam.

Essas cadeias podem ser tão longas quanto você precisar. "Usuários, os seus pedidos, os produtos desses pedidos, as categorias dos produtos e as lojas" — isso são cinco JOINs seguidos.

JOIN com WHERE

JOIN costuma vir com WHERE — JOIN cola as tabelas, WHERE filtra o resultado. Por exemplo, os pedidos da Anna acima de 1000:

SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.name = 'Anna'
  AND o.amount > 1000;

Uma combinação extremamente comum — quase qualquer consulta de negócio é "junte as tabelas + filtre com WHERE + talvez agregue".

INNER JOIN é a interseção

Em termos de teoria dos conjuntos: INNER JOIN é a interseção de duas tabelas por uma chave. Apenas as linhas presentes em ambas entram.

users       orders
  ┌──┐      ┌──┐
  │  │      │  │
  │ ●│ ←  → │● │  ← pares: apenas estes acabam no resultado
  │  │      │  │
  └──┘      └──┘

Um usuário sem pedidos — não está no resultado. Um pedido sem usuário (chave estrangeira quebrada) — também não está no resultado.

Exemplo maior: uma biblioteca

books:

idtitleauthor_id
1War and Peace10
2Anna Karenina10
3Crime and Punishment11
4The Idiot11
5(orphan — author not in DB)99

authors:

idfull_namecountry
10Leo TolstoyRussia
11Fyodor DostoevskyRussia
12Erich Maria RemarqueGermany

Consulta — cada livro com o nome do autor e o país:

SELECT b.title, a.full_name AS author, a.country
FROM books b
JOIN authors a ON a.id = b.author_id
ORDER BY a.full_name, b.title;

Resultado:

titleauthorcountry
Anna KareninaLeo TolstoyRussia
War and PeaceLeo TolstoyRussia
Crime and PunishmentFyodor DostoevskyRussia
The IdiotFyodor DostoevskyRussia

O livro órfão sumiu — author_id = 99 não está em authors. Remarque sumiu — ele tem zero livros na nossa books. O INNER JOIN descartou os dois.

Erros comuns de iniciante

1. Esquecer a cláusula ON. Escrever JOIN orders sem ON — a maioria dos bancos de dados ou dá erro ou recorre a um CROSS JOIN (produto cartesiano, cada linha vezes cada linha). Ou um erro ou uma consulta muito lenta.

2. Colunas erradas no ON. ON u.id = o.id em vez de ON u.id = o.user_id é um erro de digitação clássico. A consulta não vai quebrar — vai retornar absurdos (o usuário #5 pareado com o pedido #5, o que não tem significado).

3. Nomes de coluna ambíguos. Se tanto users quanto orders têm id, e você escreve SELECT id, name FROM users JOIN orders ON …, você obtém "a referência à coluna "id" é ambígua". Use users.id ou aliases.

4. Linhas duplicadas no resultado. Se um usuário tem 5 pedidos, o resultado tem 5 linhas com o nome desse usuário repetido. Não é um bug — é assim que o JOIN funciona. Quer usuários únicos? Envolva em SELECT DISTINCT u.name ou combine com GROUP BY.

5. Achar que o JOIN em si é lento. Os JOINs são rápidos quando há índices nas colunas de junção. É por isso que as colunas de chave estrangeira (user_id e similares) são sempre indexadas em produção.

6. Junções antigas com vírgula. Tecnicamente você pode escrever FROM users, orders WHERE users.id = orders.user_id. Não faça isso. A sintaxe moderna JOIN ... ON ... se lê melhor e separa com clareza a junção da filtragem.

Resumo rápido

  • INNER JOIN combina duas tabelas por uma chave compartilhada.
  • Apenas os pares com correspondência em ambas as tabelas entram no resultado.
  • A condição de junção vai depois de ON.
  • A palavra INNER é opcional; as pessoas escrevem apenas JOIN.
  • Você pode encadear muitos JOINs (consultas de três e cinco tabelas são normais).
  • Use aliases (users u) para manter as coisas legíveis.
  • Se você também quiser usuários sem pedidos, isso é LEFT JOIN, um cenário diferente.

Experimente você mesmo

Sobre as tabelas users e orders acima:

  1. Liste pares de nome do comprador e valor, ordenados por valor decrescente.
  2. Encontre todos os usuários que fizeram um pedido em março de 2024.
  3. Conte o valor total de pedidos por usuário (combinação JOIN + GROUP BY + SUM).

Quando o JOIN faz sentido para você, é um momento libertador ao aprender SQL. Antes — você consegue ler uma tabela. Depois — os dados do mundo real se abrem por completo.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador