DECLARE CONDITION

DECLARE CONDITION asigna un nombre descriptivo a un código de error o SQLSTATE. Esto mejora la legibilidad del código al reemplazar números crípticos con nombres significativos.

Sintaxis

DECLARE nombre_condicion CONDITION FOR codigo_error;
DECLARE nombre_condicion CONDITION FOR SQLSTATE 'valor';

Sin DECLARE CONDITION

-- El número 1062 no es autoexplicativo
DECLARE CONTINUE HANDLER FOR 1062
    SET v_error = 'Duplicado';

Con DECLARE CONDITION

-- Mucho más legible
DECLARE duplicado CONDITION FOR 1062;
DECLARE CONTINUE HANDLER FOR duplicado
    SET v_error = 'Duplicado';

Ejemplo completo

DELIMITER //
 
CREATE PROCEDURE insertar_cliente_seguro(
    IN p_nombre VARCHAR(50),
    IN p_apellidos VARCHAR(100),
    IN p_email VARCHAR(100),
    IN p_ciudad VARCHAR(50)
)
BEGIN
    DECLARE registro_duplicado CONDITION FOR 1062;
    DECLARE fk_invalida CONDITION FOR 1452;
    DECLARE v_resultado VARCHAR(200);
 
    DECLARE CONTINUE HANDLER FOR registro_duplicado
        SET v_resultado = CONCAT('Error: el email ', p_email, ' ya está registrado');
 
    DECLARE CONTINUE HANDLER FOR fk_invalida
        SET v_resultado = 'Error: referencia a datos no existentes';
 
    INSERT INTO clientes (nombre, apellidos, email, ciudad, telefono)
    VALUES (p_nombre, p_apellidos, p_email, p_ciudad, '600000000');
 
    IF v_resultado IS NULL THEN
        SET v_resultado = CONCAT('Cliente ', p_nombre, ' insertado con ID ', LAST_INSERT_ID());
    END IF;
 
    SELECT v_resultado AS resultado;
END //
 
DELIMITER ;
CALL insertar_cliente_seguro('María', 'García', 'maria.garcia@email.com', 'Madrid');
resultado
Error: el email maria.garcia@email.com ya está registrado

Condiciones con SQLSTATE

DELIMITER //
 
CREATE PROCEDURE ejemplo_sqlstate()
BEGIN
    -- Condiciones con nombre descriptivo
    DECLARE restriccion_violada CONDITION FOR SQLSTATE '23000';
    DECLARE tabla_no_existe CONDITION FOR SQLSTATE '42S02';
    DECLARE v_error VARCHAR(200);
 
    DECLARE CONTINUE HANDLER FOR restriccion_violada
        SET v_error = 'Violación de restricción de integridad';
 
    DECLARE CONTINUE HANDLER FOR tabla_no_existe
        SET v_error = 'La tabla referenciada no existe';
 
    -- Lógica...
    SELECT COALESCE(v_error, 'Sin errores') AS estado;
END //
 
DELIMITER ;

Códigos de error comunes

Código MySQLSQLSTATENombre sugeridoDescripción
106223000registro_duplicadoEntrada duplicada en índice único
145223000fk_invalidaViolación de clave foránea al insertar
145123000fk_referenciadaViolación de FK al eliminar padre
104823000campo_nuloColumna NOT NULL recibió NULL
114642S02tabla_no_existeLa tabla no existe
105442S22columna_no_existeColumna desconocida
126422003valor_fuera_rangoValor fuera de rango para el tipo
140622001dato_muy_largoDato demasiado largo para la columna

Ejemplo práctico

DELIMITER //
 
CREATE PROCEDURE transferir_stock(
    IN p_origen INT,
    IN p_destino INT,
    IN p_cantidad INT
)
BEGIN
    DECLARE producto_no_encontrado CONDITION FOR SQLSTATE '02000';
    DECLARE stock_insuficiente CONDITION FOR SQLSTATE '45000';
    DECLARE v_stock_origen INT;
    DECLARE v_error VARCHAR(200);
    DECLARE v_exito BOOLEAN DEFAULT FALSE;
 
    DECLARE CONTINUE HANDLER FOR producto_no_encontrado
        SET v_error = 'Producto no encontrado';
 
    DECLARE CONTINUE HANDLER FOR stock_insuficiente
        SET v_error = 'Stock insuficiente para la transferencia';
 
    -- Verificar origen
    SELECT stock INTO v_stock_origen FROM productos WHERE id = p_origen;
 
    IF v_stock_origen IS NULL THEN
        SET v_error = 'Producto origen no encontrado';
    ELSEIF v_stock_origen < p_cantidad THEN
        SET v_error = CONCAT('Stock insuficiente. Disponible: ', v_stock_origen);
    ELSE
        UPDATE productos SET stock = stock - p_cantidad WHERE id = p_origen;
        UPDATE productos SET stock = stock + p_cantidad WHERE id = p_destino;
        SET v_exito = TRUE;
    END IF;
 
    IF v_exito THEN
        SELECT 'Transferencia completada' AS resultado, p_cantidad AS unidades;
    ELSE
        SELECT v_error AS resultado;
    END IF;
END //
 
DELIMITER ;

Limpieza

DROP PROCEDURE IF EXISTS insertar_cliente_seguro;
DROP PROCEDURE IF EXISTS ejemplo_sqlstate;
DROP PROCEDURE IF EXISTS transferir_stock;

En el siguiente artículo veremos SIGNAL para lanzar errores personalizados desde procedimientos.

Escrito por Eduardo Lázaro