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

[El Muro del Aprendizaje de SQL] ¡Domina los JOINs! ¿Cuál es la diferencia entre INNER JOIN y LEFT JOIN?

"Tengo una lista de empleados, pero los nombres de los departamentos están en otro archivo... ¡Quiero ver una lista con el nombre del empleado y el nombre de su departamento juntos!"
"¡Quiero una lista que muestre de un vistazo qué producto pertenece a qué categoría!"

Como creador web que trabaja con bases de datos, un desafío al que casi seguro te enfrentarás es el de "querer ver la información dispersa en múltiples tablas de forma consolidada". Información del cliente e historial de compras, maestro de productos y tabla de inventario... en una base de datos normalizada, es común que la información esté dividida en tablas según su propósito.

La poderosa arma de SQL que une esta información dispersa, como si se tratara de encajar las piezas de un rompecabezas, es el "JOIN". Si dominas los JOINs, el abanico de datos que puedes manejar con SQL se expandirá exponencialmente, permitiéndote extraer información más compleja y valiosa.

En este artículo, nos centraremos en los dos tipos de JOIN más utilizados, INNER JOIN y LEFT JOIN, y explicaremos a fondo sus funciones y cómo elegir entre ellos, ¡con diagramas y código listo para copiar y pegar que hasta los principiantes entenderán sin falta!


Preparación: Tablas para Aprender a Usar JOIN

Para entender claramente cómo funcionan los JOINs, esta vez también usaremos una tabla de "empleados (employees)" y una de "departamentos (departments)". Para que las diferencias entre los JOINs sean más fáciles de ver, hemos incluido deliberadamente datos para "un nuevo aprendiz aún no asignado a un departamento" y "un nuevo departamento de Relaciones Públicas sin ningún empleado".

Por favor, copia la siguiente sentencia SQL y ejecútala en tu propio entorno de base de datos, o pruébala en el "Entorno de Ejecución de SQL" que se describe más adelante.


-- Eliminar tablas si existen
DROP TABLE IF EXISTS employees;
DROP TABLE IF EXISTS departments;

-- Crear la tabla de departamentos
CREATE TABLE departments (
    id INT PRIMARY KEY,
    department_name VARCHAR(50)
);

-- Insertar datos de departamentos
INSERT INTO departments (id, department_name) VALUES
(1, '営業部'),
(2, '開発部'),
(3, '人事部'),
(4, '広報部'); -- Un departamento sin empleados todavía

-- Crear la tabla de empleados
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT -- Permitir NULL
);

-- Insertar datos de empleados
INSERT INTO employees (id, name, department_id) VALUES
(1, '山田 太郎', 1),
(2, '鈴木 花子', 2),
(3, '佐藤 次郎', 1),
(4, '高橋 三郎', 3),
(5, '田中 恵子', 2),
(6, '中村 さくら', NULL); -- Un nuevo aprendiz aún no asignado a un departamento
    

¿Estás listo? ¡Embárcate en el viaje para conectar estas dos tablas!


1. INNER JOIN: Uniendo solo las partes comunes de dos tablas

INNER JOIN es el tipo de JOIN más básico y más utilizado. En pocas palabras, es un método de unión para "extraer solo los datos relacionados que existen en ambas tablas".

Si lo representamos con un diagrama de Venn, es como tomar solo la "intersección" donde los dos círculos se superponen. En otras palabras, lo usarías en casos en los que solo quieres información sobre "empleados que pertenecen a un departamento".

Uso Básico

Especificas la primera tabla en la cláusula FROM y la segunda tabla con INNER JOIN. Luego, en la cláusula ON, defines qué columna usar como clave para vincular las tablas entre sí.


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

Echa un vistazo a este resultado. Hay dos puntos importantes:

Esta es la principal característica de un INNER JOIN. Solo se devuelven los datos que satisfacen la condición de unión ON e.department_id = d.id, es decir, los datos que existen en ambas tablas.

※ Al definir un alias después del nombre de la tabla, como employees AS e, ¡puedes escribir consultas más cortas y convenientes!


2. LEFT JOIN: Mostrando todos los registros de una tabla

Un LEFT JOIN es un método de unión que "muestra todos los datos de la tabla de la izquierda (la primera especificada en la cláusula FROM) y adjunta los datos relacionados de la tabla de la derecha". También se le llama LEFT OUTER JOIN, pero la palabra clave `OUTER` es opcional.

En un diagrama de Venn, es como incluir todo el círculo izquierdo y solo la parte superpuesta del círculo derecho. Si no hay datos correspondientes en la tabla de la derecha, esa parte contendrá NULL (vacío).

Ejemplo 1: Mostrando todos los datos con base en los "Empleados"

Consideremos el caso en el que "quiero una lista completa de empleados. Si pertenecen a un departamento, también quiero saber el nombre del departamento". En este caso, colocamos la tabla "employees", que es nuestra base, en el lado izquierdo.


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

¡Presta atención al resultado! A diferencia del INNER JOIN, 'Nakamura Sakura', que no tiene un departamento asignado, está incluida en el resultado. Y su department_name es NULL.

Este es el poder del LEFT JOIN. Dado que se muestran todos los datos de la tabla de la izquierda (employees), es perfecto para tareas como "encontrar empleados que aún no han sido asignados a un departamento".


Ejemplo 2: Mostrando todos los datos con base en los "Departamentos"

Entonces, ¿qué pasa si intercambiamos las tablas de la izquierda y la derecha? Consideremos el caso en el que "quiero ver una lista de todos los departamentos. Si tienen empleados, quiero saber sus nombres también". Esta vez, pongamos la tabla "departments" a la izquierda.


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

¡El resultado es diferente de nuevo! El 'Departamento de Relaciones Públicas' (広報部), que no tiene empleados, ahora se muestra correctamente, y el nombre del empleado correspondiente (name) es NULL. Como puedes ver, con un LEFT JOIN, qué tabla colocas en el lado "izquierdo" es extremadamente importante.


Puntos Clave para Elegir entre INNER JOIN y LEFT JOIN

Si alguna vez te quedas atascado sobre cuál usar, solo piensa en qué quieres que sea el "protagonista" de tus datos.

Si piensas basándote en este criterio, podrás decidir de forma natural qué JOIN es el apropiado.


¡Práctica! Probemos los JOINs en tu Navegador

¡Gracias por esperar! Aquí tienes un entorno donde puedes ponerte manos a la obra y probar el INNER JOIN y el LEFT JOIN que has aprendido hasta ahora.

Copia todo el bloque de código de abajo, guárdalo como un archivo con un nombre como join_practice.html y ábrelo en tu navegador. ¡Intenta intercambiar las tablas de la izquierda y la derecha, o cambiar entre INNER y LEFT, para ver cómo cambian los resultados!


<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Patio de Pruebas de 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 a Probar los JOINs!</h1>
        <p>Introduce una sentencia SQL en el área de texto de abajo y presiona el botón "Ejecutar SQL".</p>
        <textarea id="sql-input">-- Escribe tu SQL aquí
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()">Ejecutar SQL</button>
        <div id="result-area"></div>
    </div>

    <script>
        // Inicializar la base de datos y preparar los datos
        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>La consulta devolvió 0 filas.</p>';
                }
            } catch (e) {
                resultArea.innerHTML = `<p class="error">Error: ${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;
        }

        // Visualización inicial
        executeSQL();
    </script>
</body>
</html>
    

Puntos a Tener en Cuenta y Técnicas Relacionadas

La Diferencia Entre ON y WHERE

Los principiantes a menudo se confunden sobre cuándo usar ON frente a WHERE. Recordémoslo de forma sencilla:

Piensa en ello como un flujo: primero, conectas correctamente las tablas con ON, y luego filtras solo los datos necesarios con WHERE.


RIGHT JOIN y FULL OUTER JOIN

JOIN también tiene otros miembros en su familia.

En la práctica, usarás LEFT JOIN de forma abrumadora, pero es bueno tener en un rincón de tu mente que estos otros miembros existen.


Resumen

¡Gran trabajo! Hemos explicado las diferencias y los casos de uso de INNER JOIN y LEFT JOIN, los fundamentos de la unión de tablas.

JOIN es una característica fundamental para liberar el verdadero potencial de las bases de datos relacionales. Puede parecer un poco difícil al principio, pero cuanto más lo uses, más entenderás su conveniencia y más divertido será extraer datos. ¡Por favor, prueba varios patrones y haz del JOIN tu nueva arma!