BEFORE UPDATE

Un trigger BEFORE UPDATE se ejecuta antes de que una fila existente sea modificada. Tiene acceso a OLD con los valores actuales y NEW con los valores que se van a guardar. Puede modificar NEW o cancelar la operación.

Sintaxis

DELIMITER //
 
CREATE TRIGGER nombre_trigger
BEFORE UPDATE ON nombre_tabla
FOR EACH ROW
BEGIN
    -- OLD.columna = valor actual
    -- NEW.columna = valor nuevo (modificable)
END //
 
DELIMITER ;

Validar cambios

DELIMITER //
 
CREATE TRIGGER tr_productos_before_update
BEFORE UPDATE ON productos
FOR EACH ROW
BEGIN
    -- No permitir precio negativo
    IF NEW.precio < 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'El precio no puede ser negativo';
    END IF;
 
    -- No permitir reducción de precio mayor al 50%
    IF NEW.precio < OLD.precio * 0.5 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede reducir el precio más del 50%';
    END IF;
 
    -- No permitir stock negativo
    IF NEW.stock < 0 THEN
        SET NEW.stock = 0;
    END IF;
END //
 
DELIMITER ;
-- Esto funciona: reducción del 10%
UPDATE productos SET precio = 1169.99 WHERE id = 1;
 
-- Esto falla: reducción mayor al 50%
-- UPDATE productos SET precio = 100 WHERE id = 1;
-- Error: No se puede reducir el precio más del 50%
-- Restaurar
UPDATE productos SET precio = 1299.99 WHERE id = 1;

Prevenir cambios en campos protegidos

DELIMITER //
 
CREATE TRIGGER tr_pedidos_before_update
BEFORE UPDATE ON pedidos
FOR EACH ROW
BEGIN
    -- No permitir cambiar el cliente de un pedido
    IF OLD.cliente_id != NEW.cliente_id THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede cambiar el cliente de un pedido existente';
    END IF;
 
    -- No permitir reactivar pedidos cancelados
    IF OLD.estado = 'cancelado' AND NEW.estado != 'cancelado' THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede reactivar un pedido cancelado';
    END IF;
 
    -- Validar transiciones de estado
    IF OLD.estado = 'entregado' AND NEW.estado = 'pendiente' THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede volver a estado pendiente un pedido entregado';
    END IF;
END //
 
DELIMITER ;

Ejemplo con OLD y NEW

DELIMITER //
 
CREATE TRIGGER tr_resenas_before_update
BEFORE UPDATE ON resenas
FOR EACH ROW
BEGIN
    -- Validar que la puntuación esté en rango
    IF NEW.puntuacion < 1 OR NEW.puntuacion > 5 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'La puntuación debe estar entre 1 y 5';
    END IF;
END //
 
DELIMITER ;

Limpieza

DROP TRIGGER IF EXISTS tr_productos_before_update;
DROP TRIGGER IF EXISTS tr_pedidos_before_update;
DROP TRIGGER IF EXISTS tr_resenas_before_update;

En el siguiente artículo veremos los triggers AFTER UPDATE.

Escrito por Eduardo Lázaro