Skip to main content

JOIN en SQLite

Entender, dominar y aplicar uniones entre tablas

Las bases de datos relacionales, como SQLite, almacenan información dividida en tablas. Esto es una gran ventaja: hace que los datos estén ordenados, limpios y no se repitan innecesariamente.

Pero esta partición crea una pregunta:

¿Cómo puedo obtener información que está repartida en dos o más tablas diferentes?

La respuesta es: con un JOIN.

¿Qué es realmente un JOIN?

Un JOIN es una operación que permite combinar datos de varias tablas en una sola consulta.

La definición académica dice:

JOIN es una operación relacional que produce un resultado combinando filas de dos tablas cuando sus valores cumplen una condición.

Pero vamos a explicarlo de manera más intuitiva.

1.1 Explicación intuitiva

Imagina dos listas:

  1. Una lista de clientes
  2. Una lista de pedidos

Los pedidos incluyen quién los hizo, pero no incluyen el nombre del cliente, solo un “id”.

En forma de tablas:

clients

idname
1Ana
2Luis
3Marta

orders

idclient_idtotal
1149.99
2189.90
32120.00

Si quieres obtener esta información:

Ana hizo un pedido de 49.99
Ana hizo un pedido de 89.90
Luis hizo un pedido de 120.00

Necesitas “cruzar” ambas tablas.

Eso es un JOIN.

1.2 Una frase para recordarlo

JOIN responde a la pregunta: ¿Qué ocurre cuando combino estos datos que están relacionados, pero están en tablas separadas?

Sin JOIN, una base relacional no tiene sentido completo.

¿Por qué existen los JOINs?

Los JOINs existen por tres razones fundamentales:

2.1 Evitar duplicación de datos

Si en cada pedido guardáramos el nombre del cliente, repetiríamos datos cientos de veces:

idclient_nametotal
1Ana49.99
2Ana89.90
3Ana120.00

Esto es malo porque:

  • Si Ana cambia de nombre o email → habría que actualizar cientos de filas.
  • Ocupa espacio innecesario.
  • Provoca inconsistencias.

Con JOINs:

  • mantienes los datos limpios
  • cada cosa vive donde debe vivir
  • y recuperas la información combinada solo cuando la necesitas

2.2 Convertir datos “separados” en información realmente útil

En tu tabla de pedidos aparece:

client_id = 1

Sólo con eso, un humano no sabe quién es.

JOIN te da contexto:

client_id = 1  →  Ana

JOIN convierte referencias en información clara.

2.3 Porque así funcionan TODOS los sistemas profesionales

Cualquier sistema real (ERP, CRM, ecommerce, apps de reservas, bancos, redes sociales…) funciona con múltiples tablas relacionadas.

Sin JOIN:

  • no puedes hacer informes
  • no puedes relacionar entidades
  • no puedes construir APIs completas
  • no puedes escalar un proyecto

JOIN es la llave que abre toda la potencia del SQL relacional.

¿Cuándo usar un JOIN?

Siempre que necesites una información que está repartida en varias tablas.

Ejemplos reales:

3.1 Ecommerce

  • “Mostrar productos con el nombre de su categoría”
  • “Mostrar pedidos con el nombre del cliente”
  • “Calcular la suma total de pedidos por cliente”

3.2 Gestión de empleados

  • “Mostrar empleados junto a su departamento”
  • “Mostrar tareas asignadas a cada empleado”

3.3 Cursos y alumnos

  • “Alumnos matriculados en cada curso”
  • “Cursos disponibles para un alumno”

3.4 Para el backend:

Cualquier endpoint tipo:

GET /orders → debe devolver información del cliente y del pedido
GET /products → debe incluir categoría

Para estos casos, JOIN no es opcional: es obligatorio.

Tipos de JOIN que necesitas como principiante

Hay muchos tipos de JOIN, pero en SQLite como principiante solo necesitas dominar dos:

  1. INNER JOIN
  2. LEFT JOIN

Y con esos dos puedes resolver el 95% de los problemas reales.

Preparación del entorno en DB Browser for SQLite

Vamos a crear un entorno controlado para aprender.

  1. Abre DB Browser for SQLite.
  2. Crea una base nueva:
    • Menú superior
    • Archivo
    • Nueva base de datos
    • Ponle el nombre join_tutorial.db
    • Guarda el archivo
  3. Ve a la pestaña Ejecutar SQL.
  4. Asegúrate de tener activadas las claves foráneas añadiendo esto antes de crear las tablas:
PRAGMA foreign_keys = ON;

Ejecuta esta instrucción con el botón Play.

5.1 Crear tablas

En el panel Ejecutar SQL, escribe y ejecuta:

CREATE TABLE clients (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);

CREATE TABLE orders (
id INTEGER PRIMARY KEY,
client_id INTEGER NOT NULL,
total REAL NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(id)
);

Después de ejecutar, puedes comprobar la estructura en la pestaña Estructura de DB Browser.

5.2 Insertar datos

En la misma pestaña Ejecutar SQL, borra el contenido anterior y pega:

INSERT INTO clients (name)
VALUES ('Ana'), ('Luis'), ('Marta');

INSERT INTO orders (client_id, total)
VALUES
(1, 49.99),
(1, 89.90),
(2, 120.00);

Después de ejecutarlos, revisa los datos en la pestaña Examinar datos.

Perfecto.

Ahora sí vamos a aprender JOIN.

INNER JOIN — unir datos solamente cuando hay coincidencias

INNER JOIN responde a:

“Dame solo las filas que tengan relación en ambas tablas.”

Ejecuta:

SELECT
o.id AS order_id,
c.name AS client_name,
o.total
FROM orders o
INNER JOIN clients c
ON o.client_id = c.id;

Explicación detallada

  • FROM orders o → tabla principal
  • INNER JOIN clients c → tabla que quiero unir
  • ON o.client_id = c.id → regla de unión

El motor hace esto:

  1. Toma cada pedido de la tabla orders.
  2. Busca el cliente cuyo id coincida.
  3. Si lo encuentra → combina la fila.
  4. Si NO lo encuentra → descarta esa fila.

Resultado:

order_idclient_nametotal
1Ana49.99
2Ana89.90
3Luis120.00

Observa:

  • Marta no aparece.

    No tiene pedidos, así que no hay coincidencias.

INNER JOIN es perfecto para:

  • informes de actividad
  • pedidos de clientes existentes
  • datos “completos”

LEFT JOIN — incluir incluso los que no tienen coincidencia

LEFT JOIN responde a:

“Dame todas las filas de la tabla izquierda, tengan coincidencia o no.”

Ejecuta:

SELECT
c.name AS client,
o.total
FROM clients c
LEFT JOIN orders o
ON c.id = o.client_id;

Explicación detallada

  • La tabla izquierda es clients
  • Se devolverá siempre cada cliente
  • Si tiene pedidos → aparecerán
  • Si no tiene → aparecerá con NULL

Resultado:

clienttotal
Ana49.99
Ana89.90
Luis120.00
MartaNULL

Esto es extremadamente útil para:

  • detectar clientes sin actividad
  • informes completos
  • reportes administrativos que necesitan incluir “todos”

JOIN + WHERE = consultas expresivas

Ejemplos reales:

8.1 Pedidos mayores de 80€

SELECT
c.name,
o.total
FROM clients c
JOIN orders o ON c.id = o.client_id
WHERE o.total > 80;

8.2 Pedidos de Ana

SELECT
o.id,
o.total
FROM orders o
JOIN clients c ON o.client_id = c.id
WHERE c.name = 'Ana';

8.3 Clientes sin pedidos

SELECT
c.name
FROM clients c
LEFT JOIN orders o ON c.id = o.client_id
WHERE o.id IS NULL;

Errores comunes al usar JOIN

Error 1 — No usar alias

Escribir tablas completas hace la consulta ilegible.

Error 2 — Unir por columnas incorrectas

Hay que unir por las claves relacionadas, no por columnas arbitrarias.

Error 3 — No especificar ON

Sin ON, el JOIN no sabe qué unir.

Error 4 — Usar SELECT * en JOIN complejos

Es difícil distinguir columnas.

Buenas prácticas

  • Usa alias cortos: clients c, orders o
  • Escribe el ON debajo del JOIN para legibilidad
  • Selecciona solo columnas necesarias
  • Siempre revisa los NULL en LEFT JOIN
  • Haz SELECT antes de consultas complejas para entender los datos

EJERCICIO FINAL

Vamos a realizar un ejercicio realista, paso a paso.

Paso 1 — Crear base

  1. Abre DB Browser for SQLite.
  2. Crea una base de datos nueva:
    • Archivo
    • Nueva base de datos
    • Escríbela como join_ejercicio.db
    • Guarda
  3. Ve a la pestaña Ejecutar SQL.
  4. Activa claves foráneas ejecutando:
PRAGMA foreign_keys = ON;

Paso 2 — Crear tablas

En la pestaña Ejecutar SQL, pega y ejecuta:

CREATE TABLE authors (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);

CREATE TABLE books (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
author_id INTEGER,
FOREIGN KEY (author_id) REFERENCES authors(id)
);

Puedes comprobar la estructura en la pestaña Estructura.

Paso 3 — Insertar datos

Borra el contenido del panel SQL para evitar confusión y pega:

INSERT INTO authors (name)
VALUES ('Cervantes'), ('Orwell'), ('Márquez');

INSERT INTO books (title, author_id)
VALUES
('El Quijote', 1),
('1984', 2),
('Cien Años de Soledad', 3),
('Libro huérfano', NULL);

Revisa los datos en Examinar datos.

Paso 4 — Obtener libro + autor

SELECT
b.title,
a.name AS author
FROM books b
LEFT JOIN authors a ON b.author_id = a.id;

Deberías ver:

titleauthor
El QuijoteCervantes
1984Orwell
Cien Años de SoledadMárquez
Libro huérfanoNULL

Paso 5 — Obtener solo libros con autor

SELECT
b.title,
a.name
FROM books b
JOIN authors a ON b.author_id = a.id;

Paso 6 — Mostrar autores sin libros

SELECT
a.name
FROM authors a
LEFT JOIN books b ON a.id = b.author_id
WHERE b.id IS NULL;