Integridad referencial y acciones en cascada
La integridad referencial garantiza que una clave foránea apunte a una fila válida. También define qué debe ocurrir cuando cambia o desaparece la fila referenciada.
1. Claves foráneas #
Una clave foránea debe usar columnas compatibles con la clave candidata referenciada. La columna de destino debe ser una clave primaria o estar protegida por una restricción de unicidad.
1CREATE TABLE clientes ( 2 id BIGINT PRIMARY KEY, 3 nombre VARCHAR(100) NOT NULL 4); 5 6CREATE TABLE pedidos ( 7 id BIGINT PRIMARY KEY, 8 cliente_id BIGINT NOT NULL, 9 CONSTRAINT fk_pedidos_cliente 10 FOREIGN KEY (cliente_id) 11 REFERENCES clientes(id) 12);
Sin una acción explícita, el motor normalmente impide eliminar un cliente que todavía tiene pedidos relacionados.
2. Acciones al eliminar o actualizar #
Las cláusulas ON DELETE y ON UPDATE indican cómo reaccionan las filas dependientes.
RESTRICT y NO ACTION #
Rechazan la operación cuando existen referencias. Son opciones prudentes cuando borrar la fila principal supondría perder información importante.
La diferencia entre ambas depende del motor y de si la comprobación puede aplazarse hasta el final de la sentencia o transacción. No deben considerarse siempre sinónimos perfectos.
1FOREIGN KEY (cliente_id) REFERENCES clientes(id) 2 ON DELETE RESTRICT
CASCADE #
Propaga el borrado o la actualización a las filas dependientes:
1CREATE TABLE pedido_lineas ( 2 pedido_id BIGINT NOT NULL, 3 numero INTEGER NOT NULL, 4 producto_id BIGINT NOT NULL, 5 cantidad INTEGER NOT NULL CHECK (cantidad > 0), 6 PRIMARY KEY (pedido_id, numero), 7 FOREIGN KEY (pedido_id) REFERENCES pedidos(id) 8 ON DELETE CASCADE 9);
Aquí las líneas no tienen sentido sin su pedido, por lo que la cascada expresa correctamente su ciclo de vida.
SET NULL #
Conserva la fila dependiente y elimina la referencia. La columna debe permitir NULL:
1CREATE TABLE incidencias ( 2 id BIGINT PRIMARY KEY, 3 responsable_id BIGINT, 4 FOREIGN KEY (responsable_id) REFERENCES usuarios(id) 5 ON DELETE SET NULL 6);
SET DEFAULT #
Asigna el valor predeterminado de la columna. No todos los motores lo admiten del mismo modo y el valor resultante debe seguir referenciando una fila válida.
3. Cómo elegir la acción correcta #
Decide según el significado de la relación:
- Composición: el hijo no existe sin el padre; suele encajar
ON DELETE CASCADE. - Histórico o evidencia: el hijo debe conservarse; usa
RESTRICT, borrado lógico o una referencia anulable bien justificada. - Asignación opcional: la fila puede continuar sin responsable; puede encajar
SET NULL. - Catálogo compartido: normalmente conviene impedir el borrado mientras existan referencias.
No elijas CASCADE solo para evitar errores al borrar. La acción debe coincidir con una regla del dominio.
4. Riesgos de las cascadas #
Una cascada puede recorrer varias tablas y eliminar muchas más filas de las esperadas. Antes de usarla:
- Dibuja la cadena completa de dependencias.
- Evita ciclos difíciles de razonar.
- Comprueba las limitaciones del motor sobre múltiples rutas de cascada.
- Revisa el impacto en bloqueos, registros de auditoría y replicación.
- Ejecuta eliminaciones masivas por lotes cuando el volumen lo requiera.
Las operaciones propagadas por el motor no siempre pasan por la misma lógica que una eliminación realizada por la aplicación.
5. Índices y claves foráneas #
La clave referenciada ya suele estar indexada por ser primaria o única. También suele ser recomendable indexar las columnas de la clave foránea:
1CREATE INDEX idx_pedidos_cliente_id ON pedidos(cliente_id);
Ese índice acelera uniones y ayuda al motor a localizar las filas dependientes cuando se actualiza o elimina la fila principal. Algunos motores crean ciertos índices automáticamente y otros no; compruébalo en el SGBD elegido.
6. Restricciones diferibles #
PostgreSQL y Oracle permiten aplazar determinadas comprobaciones hasta el final de la transacción:
1CONSTRAINT fk_pedidos_cliente 2 FOREIGN KEY (cliente_id) REFERENCES clientes(id) 3 DEFERRABLE INITIALLY DEFERRED
Esto resulta útil en importaciones o cambios coordinados, pero no reemplaza un orden correcto de operaciones. MySQL, SQLite y SQL Server tienen comportamientos y capacidades diferentes en este punto.
7. Borrado físico frente a borrado lógico #
Un borrado lógico suele añadir una marca como eliminado_en en lugar de ejecutar DELETE. Puede ser necesario por auditoría o recuperación, pero introduce nuevas obligaciones:
- Todas las consultas deben excluir las filas inactivas cuando corresponda.
- Las restricciones
UNIQUEpueden necesitar índices parciales o una estrategia específica del motor. - Las claves foráneas siguen apuntando a una fila físicamente existente.
- Debe existir una política de retención y purgado definitivo.
Resumen del tema
Conceptos clave #
- Las claves foráneas evitan referencias huérfanas.
CASCADE,RESTRICT,NO ACTION,SET NULLySET DEFAULTexpresan reglas distintas.- Una cascada es adecuada cuando el ciclo de vida del hijo depende realmente del padre.
- Indexar las claves foráneas suele mejorar las uniones y las operaciones sobre filas referenciadas.
- El borrado lógico conserva datos, pero desplaza complejidad a consultas, unicidad y retención.
Qué debes recordar #
La acción referencial correcta se decide por el ciclo de vida de los datos, no por cuál permite ejecutar un borrado con menos esfuerzo.