Aprende SQL

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.

videogames
id title developer_id
1Zelda1
2Mario1
3GTA V5
developers
id name
1Nintendo
5Rockstar
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 existe

4. Insertar datos inválidos (el developer_id NO existe):

INSERT INTO videogames VALUES (3, 'Juego X', 99); -- ✗ Error: 99 no existe

Con 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:

EstrategiaComportamiento
RESTRICTBloquea el borrado si hay registros que lo referencian (por defecto)
CASCADEBorra automáticamente los registros hijos
SET NULLPone 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 = 1

ON 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 = NULL

Elige bien la estrategia: CASCADE es útil cuando los hijos no tienen sentido sin el padre (ej: comentarios de un post). SET NULL es 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:

Nombre de la Tabla: developers
idname
1Nintendo
2Square Enix
3CD Projekt Red
4Mojang Studios
5Rockstar Games
Nombre de la Tabla: videogames
idtitledeveloper_idyear
1The Legend of Zelda11986
2Super Mario Bros.11985
3Final Fantasy VII21997
4The Witcher 332015
5Minecraft42011
6Grand Theft Auto V52013

Ejercicios