Claves foráneas: FOREIGN KEY
En la lección anterior vimos cómo crear tablas con CREATE TABLE. Ahora vamos a aprender a conectar tablas entre sí con claves foráneas, una pieza fundamental de las bases de datos relacionales.
¿Qué es una clave foránea?
Una clave foránea (foreign key) es una columna que hace referencia a la clave primaria de otra tabla. Su objetivo es garantizar que los datos estén relacionados de forma coherente: no puedes insertar un valor que no exista en la tabla referenciada.
INSERT ... developer_id = 1 Existe en developers → permitido INSERT ... developer_id = 99 No existe en developers → bloqueado Por ejemplo, si la tabla videogames tiene una columna developer_id, una clave foránea asegura que ese developer_id siempre corresponda a un id real en la tabla developers. Si intentas insertar un juego con developer_id = 99 y no existe ningún desarrollador con id = 99, la base de datos lo rechaza.
Sintaxis básica
La clave foránea se define dentro del CREATE TABLE:
CREATE TABLE videogames (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
developer_id INTEGER NOT NULL,
FOREIGN KEY (developer_id) REFERENCES developers(id)
);La línea FOREIGN KEY (developer_id) REFERENCES developers(id) indica que developer_id debe existir como id en la tabla developers.
Las claves foráneas no crean datos por arte de magia: la tabla referenciada (
developers) debe existir antes de crear la tabla que la referencia (videogames). El orden importa.
Activar claves foráneas en SQLite
En SQLite, las claves foráneas están desactivadas por defecto. Para que se apliquen, debes ejecutar este comando al inicio de cada conexión:
PRAGMA foreign_keys = ON;Sin este pragma, SQLite te dejará insertar cualquier valor en developer_id, aunque no exista en developers. Es un error muy común olvidarse de activarlo.
Ejemplo paso a paso
Veamos el flujo completo: crear las tablas, activar las claves foráneas e intentar insertar datos.
1. Crear la tabla padre (la que será referenciada):
CREATE TABLE developers (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
INSERT INTO developers VALUES (1, 'Nintendo'), (2, 'Valve');2. Crear la tabla hija (la que tiene la clave foránea):
CREATE TABLE videogames (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
developer_id INTEGER NOT NULL,
FOREIGN KEY (developer_id) REFERENCES developers(id)
);3. Insertar datos válidos (el developer_id existe):
INSERT INTO videogames VALUES (1, 'Zelda', 1); -- ✓ Nintendo existe
INSERT INTO videogames VALUES (2, 'Portal 2', 2); -- ✓ Valve existe4. Insertar datos inválidos (el developer_id NO existe):
INSERT INTO videogames VALUES (3, 'Juego X', 99); -- ✗ Error: 99 no existeCon PRAGMA foreign_keys = ON, esta última sentencia produce un error de integridad referencial.
¿Qué ocurre al borrar un registro referenciado?
Imagina que borras un desarrollador que tiene juegos asociados. ¿Qué pasa con esos juegos? SQL ofrece varias estrategias que se definen al crear la clave foránea:
| Estrategia | Comportamiento |
|---|---|
RESTRICT | Bloquea el borrado si hay registros que lo referencian (por defecto) |
CASCADE | Borra automáticamente los registros hijos |
SET NULL | Pone a NULL la clave foránea de los registros hijos |
ON DELETE CASCADE
Si borras un desarrollador, se borran automáticamente todos sus juegos:
CREATE TABLE videogames (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
developer_id INTEGER,
FOREIGN KEY (developer_id) REFERENCES developers(id)
ON DELETE CASCADE
);DELETE FROM developers WHERE id = 1;
-- También borra todos los juegos con developer_id = 1ON DELETE SET NULL
Si borras un desarrollador, los juegos quedan con developer_id = NULL:
CREATE TABLE videogames (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
developer_id INTEGER,
FOREIGN KEY (developer_id) REFERENCES developers(id)
ON DELETE SET NULL
);DELETE FROM developers WHERE id = 1;
-- Los juegos de Nintendo ahora tienen developer_id = NULLElige bien la estrategia:
CASCADEes útil cuando los hijos no tienen sentido sin el padre (ej: comentarios de un post).SET NULLes mejor cuando los hijos pueden existir sin la relación (ej: un empleado cuyo departamento se disuelve).
Múltiples claves foráneas
Una tabla puede tener varias claves foráneas. Por ejemplo, una tabla de puntuaciones que referencia tanto a jugadores como a juegos:
CREATE TABLE scores (
id INTEGER PRIMARY KEY,
player_id INTEGER NOT NULL,
game_id INTEGER NOT NULL,
points INTEGER NOT NULL,
FOREIGN KEY (player_id) REFERENCES players(id),
FOREIGN KEY (game_id) REFERENCES videogames(id)
);Cada INSERT en scores verificará que player_id exista en players y que game_id exista en videogames.
Nuestras tablas
Partimos de dos tablas ya creadas y relacionadas:
| id | name |
|---|---|
| 1 | Nintendo |
| 2 | Square Enix |
| 3 | CD Projekt Red |
| 4 | Mojang Studios |
| 5 | Rockstar Games |
| id | title | developer_id | year |
|---|---|---|---|
| 1 | The Legend of Zelda | 1 | 1986 |
| 2 | Super Mario Bros. | 1 | 1985 |
| 3 | Final Fantasy VII | 2 | 1997 |
| 4 | The Witcher 3 | 3 | 2015 |
| 5 | Minecraft | 4 | 2011 |
| 6 | Grand Theft Auto V | 5 | 2013 |