Introdução a Consultas com JOIN

Introdução a Consultas com JOIN

Imagine que você vai a um banco e o atendente precisa visualizar simultaneamente suas tabelas de "informações da conta" e "informações pessoais". Ele não consulta separadamente e faz a correspondência manualmente — em vez disso, ele "junta" as duas tabelas usando seu número de identificação para ver o quadro completo de uma só vez. JOIN é a mágica no SQL que permite que múltiplas tabelas "conversem" entre si.


1. Conceitos Fundamentais

Por que precisamos de JOINs?

Ao projetar um banco de dados, dividimos os dados em múltiplas tabelas para evitar redundância. Por exemplo, a tabela employees armazena apenas department_id, em vez de duplicar o nome e o endereço do departamento. Mas as consultas frequentemente precisam "remontar" as informações completas, e é aí que entram os JOINs.

SQL
-- Sem JOIN: só é possível ver department_id, não o nome do departamento
SELECT name, department_id, salary FROM employees;

-- Com JOIN: nome do funcionário e nome do departamento exibidos juntos
SELECT e.name, d.name AS department, e.salary
FROM employees e
JOIN departments d ON e.department_id = d.id;

Tipos de Relacionamento entre Tabelas

Tipo de Relacionamento Descrição Exemplo
Um-para-Um (1:1) Uma linha na tabela A corresponde a uma linha na tabela B Um usuário possui um documento de identidade
Um-para-Muitos (1:N) Uma linha na tabela A corresponde a múltiplas linhas na tabela B Um departamento tem múltiplos funcionários
Muitos-para-Muitos (M:N) Múltiplas linhas na tabela A correspondem a múltiplas linhas na tabela B Alunos e disciplinas (vinculados através da tabela de matrícula)

Em nosso banco de dados de exemplo:

Chave Estrangeira

Uma chave estrangeira é a ponte que estabelece os relacionamentos entre tabelas. É uma coluna na tabela A que referencia a chave primária da tabela B, garantindo a consistência dos dados.

SQL
-- department_id na tabela employees é uma chave estrangeira apontando para id na tabela departments
CREATE TABLE employees (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    department_id INTEGER,           -- Chave estrangeira
    salary DECIMAL(10,2),
    hire_date DATE,
    FOREIGN KEY (department_id) REFERENCES departments(id)
);
💡 Dica: Chaves estrangeiras impõem "integridade referencial" — você não pode atribuir a um funcionário um ID de departamento que não existe. Porém, no SQLite, as chaves estrangeiras são desativadas por padrão. Você precisa executar PRAGMA foreign_keys = ON; para que tenham efeito.

Sintaxe INNER JOIN

INNER JOIN retorna apenas linhas que correspondem em ambas as tabelas. Se uma linha não tiver dados correspondentes na outra tabela, ela é excluída.

SQL
SELECT nome_coluna
FROM tabela_A
INNER JOIN tabela_B ON tabela_A.coluna = tabela_B.coluna;

Condição ON

A cláusula ON especifica a condição de junção — ou seja, qual coluna é usada para correspondência entre as duas tabelas. Normalmente compara uma chave estrangeira com uma chave primária.

SQL
-- Condição ON: employees.department_id = departments.id
SELECT e.name, d.name AS department
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;

Aliases de Tabela (AS)

Quando os nomes das tabelas são longos ou você precisa distinguir colunas com o mesmo nome, você pode usar AS para criar aliases para as tabelas, simplificando a escrita:

SQL
-- Sem aliases: é necessário escrever os nomes completos toda vez
SELECT employees.name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;

-- Com aliases: mais conciso
SELECT e.name, d.name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
💡 Dica: Uma vez que um alias de tabela é definido, você deve usar o alias em toda a consulta — não é mais possível usar o nome original da tabela.


2. Sintaxe/Uso Básico

Sintaxe Completa do INNER JOIN

SQL
SELECT tabela_A.coluna1, tabela_A.coluna2, tabela_B.coluna1
FROM tabela_A
INNER JOIN tabela_B ON tabela_A.chave_estrangeira = tabela_B.chave_primaria
WHERE condição
ORDER BY nome_coluna;
💡 Dica: A palavra-chave INNER pode ser omitida — escrever apenas JOIN é equivalente a INNER JOIN.

💡 Dica: Quando um nome de coluna é único em ambas as tabelas, você pode omitir o prefixo da tabela. No entanto, é um bom hábito sempre usar prefixos para evitar ambiguidade.

💡 Dica: Um único JOIN pode conectar múltiplas tabelas — basta encadear: A JOIN B ON ... JOIN C ON ....


Exemplo: Consultar Funcionários e Seus Departamentos (Dificuldade ⭐)

A necessidade mais básica — visualizar o nome do departamento ao qual cada funcionário pertence:

SQL
SELECT e.name AS funcionario, d.name AS departamento, e.salary
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
▶ Experimente

Saída:

TEXT
funcionario  departamento  salary
-----------  ------------  --------
Zhang San    Technology    15000.00
Li Si        Technology    18000.00
Wang Wu      Marketing     12000.00
Zhao Liu     Finance       13000.00
Qian Qi      Technology    20000.00
Sun Ba       Marketing     11000.00
Wu Shi       Finance       14000.00

Nota: Zhou Jiu não aparece porque seu department_id é NULL. O INNER JOIN mantém apenas linhas que correspondem em ambas as tabelas.


Exemplo: Consultar Detalhes de Pedidos (Junção de Três Tabelas) (Dificuldade ⭐⭐)

Em cenários reais de negócio, juntar múltiplas tabelas é comum. Consultar nome do cliente, nome do produto, preço unitário e total de cada pedido:

SQL
SELECT o.customer_name, p.name AS produto,
       p.price, o.quantity,
       (p.price * o.quantity) AS total
FROM orders o
INNER JOIN products p ON o.product_id = p.id
ORDER BY total DESC;
▶ Experimente

Saída:

TEXT
customer_name  produto         price     quantity  total
-------------  --------------  --------  --------  --------
Xiao Li        iPad Air        4799.00   3         14397.00
Xiao Gang      MacBook Pro     12999.00  1         12999.00
Xiao Wang      iPhone 15       5999.00   2         11998.00
Xiao Ming      iPhone 15       5999.00   1         5999.00
Xiao Gang      iPhone 14       4999.00   1         4999.00
Xiao Hong      Magic Keyboard  999.00    5         4995.00
Xiao Ming      Apple Watch     2999.00   1         2999.00
Xiao Hong      AirPods Pro     1899.00   2         3798.00

3. Casos de Uso Comuns

Caso 1: Consultar Todos os Funcionários do Departamento de Tecnologia

Primeiro encontrar o ID do departamento via JOIN, depois filtrar com WHERE:

SQL
SELECT e.name, e.salary, e.hire_date
FROM employees e
INNER JOIN departments d ON e.department_id = d.id
WHERE d.name = 'Technology';

Saída:

TEXT
name      salary    hire_date
--------  --------  ----------
Zhang San 15000.00  2023-01-15
Li Si     18000.00  2022-06-01
Qian Qi   20000.00  2020-08-05

Caso 2: Contar Funcionários por Departamento

SQL
SELECT d.name AS departamento, COUNT(e.id) AS qtd_funcionarios
FROM departments d
INNER JOIN employees e ON d.id = e.department_id
GROUP BY d.name;

Saída:

TEXT
departamento  qtd_funcionarios
------------  ----------------
Technology    3
Marketing     2
Finance       2

❓ Perguntas Frequentes

P: Qual tem melhor desempenho, JOIN ou subconsulta? R: Em geral, JOINs têm melhor desempenho porque os mecanismos de banco de dados possuem otimizadores especializados para JOINs. Subconsultas em alguns casos podem produzir tabelas temporárias, resultando em desempenho ligeiramente inferior. No entanto, depende do volume de dados e dos índices — use EXPLAIN para verificar o plano de execução.

P: Qual é a diferença entre ON e WHERE? R: ON é a condição de junção que determina como duas tabelas são pareadas; WHERE é a condição de filtro que determina quais linhas são exibidas. Eles têm efeitos semelhantes no INNER JOIN, mas diferem significativamente no LEFT JOIN — ON não afeta a preservação da tabela da esquerda, enquanto WHERE filtra linhas NULL.

P: Aliases de tabela são obrigatórios? R: Não são obrigatórios, mas são fortemente recomendados. Aliases de tabela tornam o SQL mais conciso, especialmente em junções de múltiplas tabelas, onde melhoram significativamente a legibilidade.

P: O que acontece se uma chave estrangeira for NULL? R: O INNER JOIN excluirá essa linha porque não há dados associados correspondentes. Se você quiser manter essas linhas, use LEFT JOIN (abordado na próxima lição).


📖 Resumo


📝 Exercícios

Exercício 1 (⭐): Escreva uma consulta para exibir o nome do cliente, nome do produto e categoria do produto para todos os pedidos (requer juntar as tabelas orders e products).

Exercício 2 (⭐⭐): Escreva uma consulta para exibir o salário médio por departamento, mostrando apenas departamentos cujo salário médio excede 12000 (dica: JOIN + GROUP BY + HAVING).

Exercício 3 (⭐⭐⭐): Escreva uma consulta para exibir o valor total gasto por cada cliente em produtos, ordenado por valor total em ordem decrescente. Mostre o nome do cliente, quantidade de pedidos e valor total.


Próxima Lição

👉 08-join-types - Tipos de Junção Explicados: Aprofunde-se em LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN, CROSS JOIN e SELF JOIN, e domine a estratégia para escolher o tipo de junção correto!

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%