Volver a MySQL Básico
Procedimientos Almacenados y Triggers en MySQL
Procedimientos Almacenados
DELIMITER //
CREATE PROCEDURE crear_pedido(
IN p_cliente_id INT,
IN p_total DECIMAL(10,2),
OUT p_pedido_id INT
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
INSERT INTO pedidos(cliente_id, total, estado)
VALUES (p_cliente_id, p_total, 'pendiente');
SET p_pedido_id = LAST_INSERT_ID();
UPDATE clientes
SET total_pedidos = total_pedidos + p_total
WHERE id = p_cliente_id;
COMMIT;
END //
DELIMITER ;
-- Llamar al procedimiento
CALL crear_pedido(1, 299.99, @nuevo_id);
SELECT @nuevo_id;
Variables y Lógica de Control
DELIMITER //
CREATE PROCEDURE calcular_descuento(IN precio DECIMAL(10,2))
BEGIN
DECLARE descuento DECIMAL(10,2);
DECLARE precio_final DECIMAL(10,2);
IF precio >= 1000 THEN
SET descuento = precio * 0.20;
ELSEIF precio >= 500 THEN
SET descuento = precio * 0.10;
ELSE
SET descuento = precio * 0.05;
END IF;
SET precio_final = precio - descuento;
SELECT precio, descuento, precio_final;
END //
DELIMITER ;
Cursores
DELIMITER //
CREATE PROCEDURE procesar_pedidos_pendientes()
BEGIN
DECLARE terminado INT DEFAULT 0;
DECLARE v_id INT;
DECLARE v_total DECIMAL(10,2);
DECLARE cur CURSOR FOR
SELECT id, total FROM pedidos WHERE estado = 'pendiente';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET terminado = 1;
OPEN cur;
bucle: LOOP
FETCH cur INTO v_id, v_total;
IF terminado = 1 THEN LEAVE bucle; END IF;
UPDATE pedidos SET estado = 'procesando' WHERE id = v_id;
-- lógica de negocio aquí...
END LOOP;
CLOSE cur;
END //
DELIMITER ;
Funciones Almacenadas
DELIMITER //
CREATE FUNCTION precio_formateado(precio DECIMAL(10,2))
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
RETURN CONCAT('$', FORMAT(precio, 2));
END //
DELIMITER ;
-- Usar como función SQL normal
SELECT nombre, precio_formateado(precio) AS precio_fmt FROM productos;
Triggers
-- Trigger BEFORE INSERT para validación
DELIMITER //
CREATE TRIGGER validar_precio
BEFORE INSERT ON productos
FOR EACH ROW
BEGIN
IF NEW.precio <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'El precio debe ser mayor que 0';
END IF;
SET NEW.actualizado_en = NOW();
END //
DELIMITER ;
-- Trigger AFTER UPDATE para auditoría
DELIMITER //
CREATE TRIGGER auditar_precio
AFTER UPDATE ON productos
FOR EACH ROW
BEGIN
IF OLD.precio != NEW.precio THEN
INSERT INTO auditoria_precios(producto_id, precio_anterior, precio_nuevo, cambiado_en)
VALUES (NEW.id, OLD.precio, NEW.precio, NOW());
END IF;
END //
DELIMITER ;
Eventos Programados
-- Habilitar el planificador de eventos
SET GLOBAL event_scheduler = ON;
-- Evento para limpiar datos viejos diariamente
DELIMITER //
CREATE EVENT limpiar_sesiones_viejas
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO
BEGIN
DELETE FROM sesiones WHERE creado_en < DATE_SUB(NOW(), INTERVAL 30 DAY);
END //
DELIMITER ;