🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

[A Muralha do Aprendiz de SQL] Conquiste os JOINs! Qual é a diferença entre INNER JOIN e LEFT JOIN?

"Tenho uma lista de funcionários, mas os nomes dos departamentos estão em outro arquivo... Quero ver uma lista com o nome do funcionário e o nome do seu departamento juntos!"
"Quero uma lista que mostre de relance qual produto pertence a qual categoria!"

Como um criador web que trabalha com bancos de dados, um desafio que você quase certamente enfrentará é "querer ver informações espalhadas por várias tabelas de forma consolidada". Informações de clientes e histórico de compras, mestre de produtos e tabela de estoque... em um banco de dados normalizado, é comum que as informações sejam divididas em tabelas por finalidade.

A poderosa arma do SQL que conecta essas informações dispersas, como se estivesse montando as peças de um quebra-cabeça, é o "JOIN". Se você dominar os JOINs, a gama de dados que você pode manipular com SQL se expandirá explosivamente, permitindo que você extraia informações mais complexas e valiosas.

Neste artigo, vamos nos concentrar em dois dos JOINs mais frequentemente usados, INNER JOIN e LEFT JOIN, e explicar detalhadamente suas funções e como escolher entre eles, com diagramas e código pronto para copiar e colar que até mesmo os iniciantes entenderão com certeza!


Preparação: Tabelas para Aprender a Usar JOIN

Para entender claramente como os JOINs funcionam, desta vez também usaremos uma tabela de "funcionários (employees)" e uma de "departamentos (departments)". Para tornar as diferenças entre os JOINs fáceis de ver, incluímos deliberadamente dados para "um novo estagiário ainda não atribuído a um departamento" e "um novo departamento de Relações Públicas sem nenhum funcionário".

Por favor, copie a instrução SQL abaixo e execute-a em seu próprio ambiente de banco de dados, ou experimente-a no "Ambiente de Execução de SQL" descrito mais adiante.


-- Excluir tabelas se existirem
DROP TABLE IF EXISTS employees;
DROP TABLE IF EXISTS departments;

-- Criar a tabela de departamentos
CREATE TABLE departments (
    id INT PRIMARY KEY,
    department_name VARCHAR(50)
);

-- Inserir dados dos departamentos
INSERT INTO departments (id, department_name) VALUES
(1, '営業部'),
(2, '開発部'),
(3, '人事部'),
(4, '広報部'); -- Um departamento ainda sem funcionários

-- Criar a tabela de funcionários
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT -- Permitir NULL
);

-- Inserir dados dos funcionários
INSERT INTO employees (id, name, department_id) VALUES
(1, '山田 太郎', 1),
(2, '鈴木 花子', 2),
(3, '佐藤 次郎', 1),
(4, '高橋 三郎', 3),
(5, '田中 恵子', 2),
(6, '中村 さくら', NULL); -- Um novo estagiário ainda não atribuído a um departamento
    

Pronto? Vamos embarcar na jornada para conectar estas duas tabelas!


1. INNER JOIN: Juntando Apenas as Partes Comuns de Duas Tabelas

INNER JOIN é o tipo de JOIN mais básico e mais comumente usado. Em poucas palavras, é um método de junção para "extrair apenas os dados relacionados que existem em ambas as tabelas".

Se você o visualizar com um diagrama de Venn, é como pegar apenas a "interseção" onde os dois círculos se sobrepõem. Em outras palavras, você o usaria em casos em que deseja apenas informações sobre "funcionários que pertencem a um departamento".

Uso Básico

Você especifica a primeira tabela na cláusula FROM e a segunda tabela com INNER JOIN. Em seguida, na cláusula ON, você define qual coluna usar como chave para vincular as tabelas.


SELECT
    e.name,
    d.department_name
FROM
    employees AS e
INNER JOIN
    departments AS d ON e.department_id = d.id;
    

Dê uma olhada neste resultado. Existem dois pontos importantes:

Esta é a principal característica de um INNER JOIN. Apenas os dados que satisfazem a condição de junção ON e.department_id = d.id — ou seja, dados que existem em ambas as tabelas — são retornados.

※ Ao definir um alias após o nome da tabela, como employees AS e, você pode escrever consultas mais curtas e convenientes!


2. LEFT JOIN: Exibindo Todos os Registros de Uma Tabela

Um LEFT JOIN é um método de junção que "exibe todos os dados da tabela da esquerda (a primeira especificada na cláusula FROM) e anexa os dados relacionados da tabela da direita". Também é chamado de LEFT OUTER JOIN, mas a palavra-chave `OUTER` é opcional.

Em um diagrama de Venn, é como incluir todo o círculo esquerdo e apenas a parte sobreposta do círculo direito. Se não houver dados correspondentes na tabela da direita, essa parte conterá NULL (vazio).

Exemplo 1: Exibindo todos os dados com base nos "Funcionários"

Vamos considerar o caso em que "quero uma lista completa de funcionários. Se eles pertencerem a um departamento, também quero saber o nome do departamento". Neste caso, colocamos a tabela "employees", que é a nossa base, no lado esquerdo.


SELECT
    e.name,
    d.department_name
FROM
    employees AS e
LEFT JOIN
    departments AS d ON e.department_id = d.id;
    

Preste atenção ao resultado! Ao contrário do INNER JOIN, 'Nakamura Sakura', que não tem um departamento atribuído, está incluída no resultado. E o seu department_name é NULL.

Este é o poder do LEFT JOIN. Como todos os dados da tabela da esquerda (employees) são exibidos, é perfeito para tarefas como "encontrar funcionários que ainda não foram atribuídos a um departamento".


Exemplo 2: Exibindo todos os dados com base nos "Departamentos"

Então, o que acontece se trocarmos as tabelas da esquerda e da direita? Vamos considerar o caso em que "quero ver uma lista de todos os departamentos. Se tiverem funcionários, quero saber os nomes deles também". Desta vez, vamos colocar a tabela "departments" à esquerda.


SELECT
    d.department_name,
    e.name
FROM
    departments AS d
LEFT JOIN
    employees AS e ON d.id = e.department_id;
    

O resultado é diferente novamente! O 'Departamento de Relações Públicas' (広報部), que não tem funcionários, agora é exibido corretamente, e o nome do funcionário correspondente (name) é NULL. Como você pode ver, com um LEFT JOIN, qual tabela você coloca no lado "esquerdo" é extremamente importante.


Pontos-Chave para Escolher entre INNER JOIN e LEFT JOIN

Se você alguma vez ficar em dúvida sobre qual usar, apenas pense no que você quer que seja o "protagonista" dos seus dados.

Se você pensar com base neste critério, será capaz de decidir naturalmente qual JOIN é o apropriado.


Prática! Vamos Experimentar os JOINs no seu Navegador

Obrigado por esperar! Aqui está um ambiente onde você pode colocar a mão na massa e experimentar o INNER JOIN e o LEFT JOIN que aprendeu até agora.

Copie o bloco de código inteiro abaixo, salve-o como um arquivo com um nome como join_practice.html e abra-o no seu navegador. Tente trocar as tabelas da esquerda e da direita, ou alternar entre INNER e LEFT, para ver como os resultados mudam!


<!DOCTYPE html>
<html lang="pt">
<head>
    <meta charset="UTF-8">
    <title>Ambiente de Testes para SQL JOIN</title>
    <script src="https://cdn.jsdelivr.net/npm/alasql@4"></script>
    <style>
        body { font-family: sans-serif; padding: 2rem; background-color: #f9f9f9; }
        .container { max-width: 800px; margin: auto; background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
        h1 { color: #333; }
        textarea { width: 100%; height: 180px; font-family: monospace; font-size: 16px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; margin-bottom: 1rem; }
        button { background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
        button:hover { background-color: #0056b3; }
        #result-area { margin-top: 2rem; }
        table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        .error { color: red; font-weight: bold; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Vamos Experimentar os JOINs!</h1>
        <p>Insira uma instrução SQL na área de texto abaixo e pressione o botão "Executar SQL".</p>
        <textarea id="sql-input">-- Escreva seu SQL aqui
SELECT
    e.name,
    d.department_name
FROM
    employees AS e
LEFT JOIN
    departments AS d ON e.department_id = d.id;</textarea>
        <button onclick="executeSQL()">Executar SQL</button>
        <div id="result-area"></div>
    </div>

    <script>
        // Inicializar o banco de dados e preparar os dados
        const db = new alasql.Database();
        db.exec(`
            CREATE TABLE departments (id INT, department_name STRING);
            INSERT INTO departments VALUES (1, '営業部'), (2, '開発部'), (3, '人事部'), (4, '広報部');

            CREATE TABLE employees (id INT, name STRING, department_id INT);
            INSERT INTO employees VALUES (1, '山田 太郎', 1), (2, '鈴木 花子', 2), (3, '佐藤 次郎', 1), (4, '高橋 三郎', 3), (5, '田中 恵子', 2), (6, '中村 さくら', NULL);
        `);

        function executeSQL() {
            const sql = document.getElementById('sql-input').value;
            const resultArea = document.getElementById('result-area');
            resultArea.innerHTML = '';

            try {
                const result = db.exec(sql);
                if (result.length > 0) {
                    resultArea.appendChild(createTable(result));
                } else {
                    resultArea.innerHTML = '<p>A consulta retornou 0 linhas.</p>';
                }
            } catch (e) {
                resultArea.innerHTML = `<p class="error">Erro: ${e.message}</p>`;
            }
        }

        function createTable(data) {
            const table = document.createElement('table');
            const thead = table.createTHead();
            const tbody = table.createTBody();
            const headerRow = thead.insertRow();
            for (const key in data[0]) {
                const th = document.createElement('th');
                th.textContent = key;
                headerRow.appendChild(th);
            }
            data.forEach(rowData => {
                const row = tbody.insertRow();
                for (const key in rowData) {
                    const cell = row.insertCell();
                    cell.textContent = (rowData[key] === null || rowData[key] === undefined) ? 'NULL' : rowData[key];
                }
            });
            return table;
        }

        // Exibição inicial
        executeSQL();
    </script>
</body>
</html>
    

Pontos de Atenção e Técnicas Relacionadas

A Diferença Entre ON e WHERE

Os iniciantes muitas vezes se confundem sobre quando usar ON em vez de WHERE. Vamos lembrar de forma simples:

Pense nisso como um fluxo: primeiro, você conecta corretamente as tabelas com ON, e depois filtra apenas os dados necessários com WHERE.


RIGHT JOIN e FULL OUTER JOIN

O JOIN também tem outros membros na família.

Na prática, você usará o LEFT JOIN com uma frequência esmagadora, mas é bom ter em um canto da sua mente que estes outros membros existem.


Resumo

Ótimo trabalho! Explicamos as diferenças e os casos de uso de INNER JOIN e LEFT JOIN, os fundamentos da junção de tabelas.

JOIN é um recurso fundamental para liberar o verdadeiro potencial dos bancos de dados relacionais. Pode parecer um pouco difícil no início, mas quanto mais você o usa, mais entenderá sua conveniência e mais divertido se tornará extrair dados. Por favor, experimente vários padrões e faça do JOIN sua nova arma!