AFTER UPDATE

Un trigger AFTER UPDATE se ejecuta después de que una fila ha sido modificada exitosamente. Tiene acceso a OLD y NEW pero no puede modificar ninguno. Es ideal para auditoría y sincronización. Para validar o transformar datos antes de la modificación, usa BEFORE UPDATE.

Sintaxis

DELIMITER //
 
CREATE TRIGGER nombre_trigger
AFTER UPDATE ON nombre_tabla
FOR EACH ROW
BEGIN
    -- OLD.columna = valor anterior
    -- NEW.columna = valor nuevo
    -- No se pueden modificar
END //
 
DELIMITER ;

Auditoría de cambios de precio

CREATE TABLE IF NOT EXISTS auditoria_precios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    producto_id INT,
    nombre_producto VARCHAR(100),
    precio_anterior DECIMAL(10,2),
    precio_nuevo DECIMAL(10,2),
    diferencia DECIMAL(10,2),
    porcentaje_cambio DECIMAL(5,2),
    usuario VARCHAR(100),
    fecha DATETIME DEFAULT NOW()
);
DELIMITER //
 
CREATE TRIGGER tr_audit_precio
AFTER UPDATE ON productos
FOR EACH ROW
BEGIN
    IF OLD.precio != NEW.precio THEN
        INSERT INTO auditoria_precios
            (producto_id, nombre_producto, precio_anterior, precio_nuevo,
             diferencia, porcentaje_cambio, usuario)
        VALUES
            (NEW.id, NEW.nombre, OLD.precio, NEW.precio,
             NEW.precio - OLD.precio,
             ROUND((NEW.precio - OLD.precio) / OLD.precio * 100, 2),
             USER());
    END IF;
END //
 
DELIMITER ;
UPDATE productos SET precio = 1399.99 WHERE id = 1;
 
SELECT * FROM auditoria_precios;
idproducto_idnombre_productoprecio_anteriorprecio_nuevodiferenciaporcentaje_cambio
11iPhone 15 Pro1299.991399.99100.007.69
-- Restaurar
UPDATE productos SET precio = 1299.99 WHERE id = 1;

Historial de estados

Registrar cada cambio de estado en una tabla de historial es un patrón habitual de auditoría. Este tipo de registro es especialmente útil cuando se combina con transacciones, ya que el INSERT en la tabla de historial y el UPDATE original se revierten juntos si hay un error:

CREATE TABLE IF NOT EXISTS historial_pedidos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    pedido_id INT,
    estado_anterior VARCHAR(20),
    estado_nuevo VARCHAR(20),
    fecha DATETIME DEFAULT NOW()
);
DELIMITER //
 
CREATE TRIGGER tr_pedidos_historial
AFTER UPDATE ON pedidos
FOR EACH ROW
BEGIN
    IF OLD.estado != NEW.estado THEN
        INSERT INTO historial_pedidos (pedido_id, estado_anterior, estado_nuevo)
        VALUES (NEW.id, OLD.estado, NEW.estado);
    END IF;
END //
 
DELIMITER ;

AFTER UPDATE vs BEFORE UPDATE

CaracterísticaBEFORE UPDATEAFTER UPDATE
MomentoAntes del cambioDespués del cambio
Modificar NEWNo
Cancelar operaciónSí, con SIGNALNo, ya se actualizó
Uso principalValidaciónAuditoría, sincronización
Datos consistentesNEW puede ser modificadoOLD y NEW son definitivos

Limpieza

DROP TRIGGER IF EXISTS tr_audit_precio;
DROP TRIGGER IF EXISTS tr_pedidos_historial;
DROP TABLE IF EXISTS auditoria_precios;
DROP TABLE IF EXISTS historial_pedidos;

En el siguiente artículo veremos los triggers BEFORE DELETE.

Escrito por Eduardo Lázaro