SQL

Claves foráneas (Foreign Keys) en SQL

Una clave foránea (foreign key) es una restricción (constraint) de integridad referencial que vincula una o más columnas de una tabla con la clave primaria o única de otra tabla. Su función práctica principal es impedir la inserción de registros huérfanos y evitar que se eliminen datos de la tabla referenciada si existen dependencias activas.

Definición en línea (Column Level)

La definición en línea declara la referencia directamente en la misma línea en la que se crea la columna. Se usa cuando la clave foránea depende de un único campo y se busca una sintaxis compacta.

Sintaxis

CREATE TABLE <nombre_tabla> (
    <columna> <tipo_dato> [NULL | NOT NULL] REFERENCES <tabla_referenciada>(<columna_destino>)
);

Desglose de elementos

  • <columna>: Nombre del campo local que almacena el identificador de la otra tabla.
  • <tipo_dato>: Tipo de dato del campo local. Debe coincidir estrictamente con el tipo de dato de la clave de destino.
  • REFERENCES: Cláusula que declara el destino de la relación.
  • <tabla_referenciada>(<columna_destino>): Nombre de la tabla padre y la columna exacta que se toma como referencia.

Ejemplo práctico

CREATE TABLE clientes (
    id INT IDENTITY(1,1) PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL
);

CREATE TABLE pedidos (
    id INT IDENTITY(1,1) PRIMARY KEY,
    cliente_id INT NOT NULL REFERENCES clientes(id),
    total DECIMAL(10,2) NOT NULL
);

⚠️ Cuidado: Cuando definís una clave foránea en línea, el motor de base de datos le asigna un nombre interno aleatorio por defecto (por ejemplo, FK__pedidos__client__4D94879B). Esto complica el mantenimiento posterior si necesitás eliminar o modificar la restricción.

Definición explícita como restricción de tabla (Table Level)

Declarar la relación como un CONSTRAINT al final de la definición de la tabla permite asignar un nombre representativo a la regla y separar la definición de tipos de datos de la lógica de integridad.

Sintaxis

CREATE TABLE <nombre_tabla> (
    <columna_1> <tipo_dato> [NULL | NOT NULL],
    <columna_fk> <tipo_dato> [NULL | NOT NULL],
    CONSTRAINT <nombre_fk> FOREIGN KEY (<columna_fk>) REFERENCES <tabla_referenciada>(<columna_destino>)
);

Desglose de elementos

  • CONSTRAINT <nombre_fk>: Asigna un identificador explícito a la regla (por convención: FK_<TablaOrigen>_<TablaDestino>).
  • FOREIGN KEY (<columna_fk>): Especifica qué columna local actúa como enlace.
  • REFERENCES <tabla_referenciada>(<columna_destino>): Define la tabla y columna externa a la cual apunta el enlace.

Ejemplo práctico

CREATE TABLE pedidos (
    id INT IDENTITY(1,1),
    cliente_id INT NOT NULL,
    total DECIMAL(10,2) NOT NULL,
    CONSTRAINT PK_pedidos PRIMARY KEY (id),
    CONSTRAINT FK_pedidos_clientes FOREIGN KEY (cliente_id) REFERENCES clientes(id)
);

💡 Consejo: Usá siempre nombres explícitos para tus restricciones. Facilitan la lectura de los scripts de migración y permiten identificar con rapidez qué regla falló cuando el motor arroja un error de integridad.

Claves foráneas compuestas

Una clave foránea compuesta referencia una clave primaria o única que está formada por dos o más columnas. En estos casos, es obligatorio definir la restricción a nivel de tabla (al final de la lista de columnas), ya que no es posible asociar múltiples columnas dentro de la declaración de un solo campo.

Sintaxis

CONSTRAINT <nombre_fk> FOREIGN KEY (<columna_local_1>, <columna_local_2>) REFERENCES <tabla_referenciada>(<columna_destino_1>, <columna_destino_2>)

Desglose de elementos

  • (<columna_local_1>, <columna_local_2>): Columnas de la tabla actual que forman la clave compuesta.
  • REFERENCES <tabla_referenciada>(<columna_destino_1>, <columna_destino_2>): Columnas de la tabla padre. El orden, la cantidad de columnas y los tipos de datos deben coincidir de forma idéntica con los definidos en la tabla origen.

Ejemplo práctico

CREATE TABLE sucursales_empleados (
    empresa_id INT NOT NULL,
    sucursal_id INT NOT NULL,
    nombre VARCHAR(100) NOT NULL,
    CONSTRAINT PK_sucursales_empleados PRIMARY KEY (empresa_id, sucursal_id)
);

CREATE TABLE turnos_trabajo (
    id INT IDENTITY(1,1) PRIMARY KEY,
    empresa_id INT NOT NULL,
    sucursal_id INT NOT NULL,
    fecha DATE NOT NULL,
    CONSTRAINT FK_turnos_sucursales FOREIGN KEY (empresa_id, sucursal_id) 
        REFERENCES sucursales_empleados(empresa_id, sucursal_id)
);

Creación y modificación con ALTER TABLE

Definir las claves foráneas por fuera del CREATE TABLE inicial permite desacoplar la creación de esquemas y resuelve bloqueos por dependencias circulares (cuando la tabla A apunta a la tabla B y la tabla B apunta a la tabla A).

Sintaxis

ALTER TABLE <nombre_tabla>
ADD CONSTRAINT <nombre_fk> FOREIGN KEY (<columna_local>) REFERENCES <tabla_referenciada>(<columna_destino>)
[ON DELETE <accion>] [ON UPDATE <accion>];

Desglose de elementos

  • ALTER TABLE <nombre_tabla>: Especifica la tabla sobre la cual se inyecta la restricción.
  • ADD CONSTRAINT <nombre_fk>: Agrega la nueva regla de integridad con su nombre formal.
  • ON DELETE / ON UPDATE: Cláusulas opcionales que indican qué acción ejecutar cuando el registro padre se elimina o actualiza (CASCADE, SET NULL, SET DEFAULT, NO ACTION).

Ejemplo práctico

-- Creación de tablas con dependencia mutua
CREATE TABLE empleados (
    id INT IDENTITY(1,1) PRIMARY KEY,
    nombre VARCHAR(50) NOT NULL,
    departamento_id INT NULL
);

CREATE TABLE departamentos (
    id INT IDENTITY(1,1) PRIMARY KEY,
    descripcion VARCHAR(50) NOT NULL,
    director_id INT NULL
);

-- Creación posterior de las relaciones para evitar dependencias cruzadas
ALTER TABLE empleados
ADD CONSTRAINT FK_empleados_departamentos 
FOREIGN KEY (departamento_id) REFERENCES departamentos(id);

ALTER TABLE departamentos
ADD CONSTRAINT FK_departamentos_empleados 
FOREIGN KEY (director_id) REFERENCES empleados(id);

Tabla de referencia: Acciones referenciales (ON DELETE / ON UPDATE)

Comando / Opción Descripción
NO ACTION Opción por defecto. Rechaza la eliminación o modificación si existen filas dependientes.
CASCADE Propaga la eliminación o actualización a todas las filas vinculadas en la tabla secundaria.
SET NULL Asigna NULL a la columna foránea en las filas vinculadas (requiere que la columna permita nulos).
SET DEFAULT Establece el valor por defecto configurado para la columna en las filas dependientes.

⚠️ Cuidado: Al ejecutar ALTER TABLE ... ADD CONSTRAINT, el motor valida que todos los registros ya existentes en la tabla cumplan con la integridad referencial. Si hay filas con valores que no existen en la tabla destino, el comando falla.