EL CHECK CONSTRAINT EN MYSQL: CÓMO GARANTIZAR LA INTEGRIDAD DE LOS DATOS
El constraintSintaxis
- A nivel de columna:
columna TIPO_DATO [CONSTRAINT nombre] CHECK (condición) - A nivel de tabla (después de definir todas las columnas):
[CONSTRAINT nombre_constraint] CHECK (condición) //También se puede indicar si la restricción está enforced (aplicada) o no: CHECK (condición) [NOT] ENFORCED
Ejemplos prácticos
- CHECK simple a nivel de columna:
CREATE TABLE empleados ( id INT PRIMARY KEY AUTO_INCREMENT, nombre VARCHAR(100) NOT NULL, edad INT CHECK (edad >= 18), -- Debe ser mayor o igual a 18 salario DECIMAL(10,2) CHECK (salario > 0), -- Salario positivo estado_civil ENUM('soltero', 'casado', 'viudo') ); - CHECK a nivel de tabla con nombre (recomendado):
CREATE TABLE productos ( id INT PRIMARY KEY AUTO_INCREMENT, nombre VARCHAR(150) NOT NULL, precio DECIMAL(10,2) NOT NULL, stock INT NOT NULL DEFAULT 0, descuento DECIMAL(5,2) DEFAULT 0.00, CONSTRAINT chk_precio_positivo CHECK (precio > 0), CONSTRAINT chk_stock_no_negativo CHECK (stock >= 0), CONSTRAINT chk_descuento_valido CHECK (descuento >= 0 AND descuento <= precio * 0.8), CONSTRAINT chk_precio_mayor_descuento CHECK (precio > descuento) ); - CHECK complejo con múltiples columnas y lógica condicional: Este es uno de los usos más potentes del CHECK.
CREATE TABLE pedidos ( id INT PRIMARY KEY AUTO_INCREMENT, tipo ENUM('normal', 'express', 'urgente') NOT NULL, fecha_entrega DATE NOT NULL, costo_envio DECIMAL(8,2) DEFAULT 0.00, CONSTRAINT chk_fecha_entrega CHECK ( (tipo = 'normal' AND fecha_entrega >= DATE_ADD(CURRENT_DATE, INTERVAL 3 DAY)) OR (tipo = 'express' AND fecha_entrega >= DATE_ADD(CURRENT_DATE, INTERVAL 1 DAY)) OR (tipo = 'urgente' AND fecha_entrega >= CURRENT_DATE) ), CONSTRAINT chk_costo_envio CHECK ( (tipo = 'normal' AND costo_envio = 0) OR (tipo IN ('express', 'urgente') AND costo_envio > 0) ) ); - Añadir un CHECK a una tabla existente:
ALTER TABLE empleados ADD CONSTRAINT chk_edad_adulta CHECK (edad >= 18 AND edad <= 70); - Desactivar temporalmente una restricción (útil en migraciones):
Atención: Cuando se vuelve a activar "ENFORCED", MySQL no valida los datos existentes automáticamente. Si se quiere validar todo, es mejor eliminar y volver a crear la restricción.ALTER TABLE empleados ALTER CHECK chk_edad_adulta NOT ENFORCED; -- ... realizar operaciones masivas ... ALTER TABLE empleados ALTER CHECK chk_edad_adulta ENFORCED; - Cómo ver las restricciones CHECK existentes:
//Para ejecutar esta query hay que tener permisos para usar la bbdd "information_schema" -- Ver todas las CHECK constraints del esquema actual SELECT * FROM information_schema.CHECK_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = DATABASE(); -- Ver la definición de una tabla con sus constraints SHOW CREATE TABLE empleados; - Cómo eliminar un CHECK constraint:
ALTER TABLE empleados DROP CHECK chk_edad_adulta;
Limitaciones importantes del CHECK en MySQL
- No permite subconsultas (SELECT ... dentro del CHECK).
- No puede referenciar columnas de otras tablas.
- No puede usar funciones no determinísticas (como RAND(), NOW() en algunos contextos) ni variables de usuario.
- No puede referenciar columnas AUTO_INCREMENT.
- Las expresiones deben ser booleanas (evaluar a TRUE o UNKNOWN). Si evalúa a FALSE, se rechaza la operación.
Ventajas de usar CHECK constraints
- La validación se realiza en el servidor, independientemente de la aplicación que acceda a la base de datos.
- Reduce errores de datos corruptos.
- Mejora la documentación del esquema (las reglas de negocio quedan visibles en la DDL).
- Aumenta la portabilidad del modelo de datos hacia otros motores SQL.