SIGNAL
SIGNAL lanza un error o advertencia personalizada desde un procedimiento almacenado. Es el equivalente a throw en Java o raise en Python. Permite crear mensajes de error descriptivos y específicos para tu lógica de negocio.
Sintaxis
SIGNAL SQLSTATE 'valor'
SET MESSAGE_TEXT = 'mensaje de error',
MYSQL_ERRNO = codigo;SQLSTATE para errores personalizados
El SQLSTATE '45000' está reservado para errores definidos por el usuario:
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Error personalizado';Ejemplo básico
DELIMITER //
CREATE PROCEDURE verificar_edad(IN edad INT)
BEGIN
IF edad < 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'La edad no puede ser negativa';
ELSEIF edad > 150 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'La edad no parece válida';
END IF;
SELECT CONCAT('Edad válida: ', edad) AS resultado;
END //
DELIMITER ;CALL verificar_edad(25);| resultado |
|---|
| Edad válida: 25 |
-- CALL verificar_edad(-5);
-- Error 1644 (45000): La edad no puede ser negativaPropiedades de SIGNAL
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Descripción del error',
MYSQL_ERRNO = 5001,
TABLE_NAME = 'productos',
COLUMN_NAME = 'precio';| Propiedad | Descripción |
|---|---|
| MESSAGE_TEXT | Mensaje descriptivo del error |
| MYSQL_ERRNO | Código de error numérico personalizado |
| TABLE_NAME | Nombre de tabla relacionada |
| COLUMN_NAME | Nombre de columna relacionada |
| SCHEMA_NAME | Nombre del esquema |
| CURSOR_NAME | Nombre del cursor |
Validación de datos
DELIMITER //
CREATE PROCEDURE crear_producto(
IN p_nombre VARCHAR(100),
IN p_precio DECIMAL(10,2),
IN p_stock INT,
IN p_categoria_id INT
)
BEGIN
-- Validaciones
IF p_nombre IS NULL OR TRIM(p_nombre) = '' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'El nombre del producto es obligatorio',
MYSQL_ERRNO = 5001;
END IF;
IF p_precio IS NULL OR p_precio <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'El precio debe ser mayor que cero',
MYSQL_ERRNO = 5002;
END IF;
IF p_stock IS NULL OR p_stock < 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'El stock no puede ser negativo',
MYSQL_ERRNO = 5003;
END IF;
-- Verificar que la categoría existe
IF NOT EXISTS (SELECT 1 FROM categorias WHERE id = p_categoria_id) THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'La categoría especificada no existe',
MYSQL_ERRNO = 5004;
END IF;
-- Si todas las validaciones pasan, insertar
INSERT INTO productos (nombre, precio, stock, categoria_id, activo)
VALUES (p_nombre, p_precio, p_stock, p_categoria_id, TRUE);
SELECT LAST_INSERT_ID() AS nuevo_id, p_nombre AS producto;
END //
DELIMITER ;-- CALL crear_producto('', 100, 10, 6);
-- Error 1644 (45000): El nombre del producto es obligatorio
-- CALL crear_producto('Test', -50, 10, 6);
-- Error 1644 (45000): El precio debe ser mayor que ceroSIGNAL como advertencia
Puedes lanzar advertencias en lugar de errores usando un SQLSTATE que empiece con '01':
DELIMITER //
CREATE PROCEDURE verificar_stock_minimo(IN prod_id INT)
BEGIN
DECLARE v_nombre VARCHAR(100);
DECLARE v_stock INT;
SELECT nombre, stock INTO v_nombre, v_stock
FROM productos WHERE id = prod_id;
IF v_stock < 10 THEN
SIGNAL SQLSTATE '01000'
SET MESSAGE_TEXT = 'Stock bajo, considerar reposición';
END IF;
SELECT v_nombre AS producto, v_stock AS stock;
END //
DELIMITER ;Capturar errores SIGNAL
DELIMITER //
CREATE PROCEDURE ejemplo_capturar_signal()
BEGIN
DECLARE v_error VARCHAR(200);
DECLARE CONTINUE HANDLER FOR SQLSTATE '45000'
BEGIN
GET DIAGNOSTICS CONDITION 1
v_error = MESSAGE_TEXT;
END;
-- Esto lanza un SIGNAL
CALL verificar_edad(-10);
IF v_error IS NOT NULL THEN
SELECT CONCAT('Error capturado: ', v_error) AS resultado;
END IF;
END //
DELIMITER ;Condición nombrada con SIGNAL
DELIMITER //
CREATE PROCEDURE ejemplo_condicion_signal()
BEGIN
DECLARE precio_invalido CONDITION FOR SQLSTATE '45000';
IF TRUE THEN -- Ejemplo simplificado
SIGNAL precio_invalido
SET MESSAGE_TEXT = 'El precio no es válido para esta operación';
END IF;
END //
DELIMITER ;Limpieza
DROP PROCEDURE IF EXISTS verificar_edad;
DROP PROCEDURE IF EXISTS crear_producto;
DROP PROCEDURE IF EXISTS verificar_stock_minimo;
DROP PROCEDURE IF EXISTS ejemplo_capturar_signal;
DROP PROCEDURE IF EXISTS ejemplo_condicion_signal;En el siguiente artículo veremos RESIGNAL para relanzar o modificar errores dentro de un handler.
Escrito por Eduardo Lázaro
