BEFORE DELETE

Un trigger BEFORE DELETE se ejecuta antes de que una fila sea eliminada de la tabla. Tiene acceso a OLD con los valores que se van a eliminar. Puede cancelar la eliminación con SIGNAL.

Sintaxis

DELIMITER //
 
CREATE TRIGGER nombre_trigger
BEFORE DELETE ON nombre_tabla
FOR EACH ROW
BEGIN
    -- OLD.columna contiene los valores que se van a eliminar
    -- NEW no está disponible en DELETE
END //
 
DELIMITER ;

Prevenir eliminaciones

DELIMITER //
 
CREATE TRIGGER tr_productos_before_delete
BEFORE DELETE ON productos
FOR EACH ROW
BEGIN
    DECLARE v_pedidos INT;
 
    SELECT COUNT(*) INTO v_pedidos
    FROM detalle_pedidos WHERE producto_id = OLD.id;
 
    IF v_pedidos > 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede eliminar un producto con pedidos asociados';
    END IF;
END //
 
DELIMITER ;
-- Esto falla si el producto tiene pedidos
-- DELETE FROM productos WHERE id = 1;
-- Error: No se puede eliminar un producto con pedidos asociados

Archivar antes de eliminar

CREATE TABLE IF NOT EXISTS productos_archivados (
    id INT,
    nombre VARCHAR(100),
    precio DECIMAL(10,2),
    stock INT,
    categoria_id INT,
    fecha_archivado DATETIME DEFAULT NOW()
);
DELIMITER //
 
CREATE TRIGGER tr_archivar_producto
BEFORE DELETE ON productos
FOR EACH ROW
BEGIN
    INSERT INTO productos_archivados (id, nombre, precio, stock, categoria_id)
    VALUES (OLD.id, OLD.nombre, OLD.precio, OLD.stock, OLD.categoria_id);
END //
 
DELIMITER ;

Soft delete con trigger

En lugar de eliminar físicamente, puedes forzar el uso de desactivación:

DELIMITER //
 
CREATE TRIGGER tr_soft_delete
BEFORE DELETE ON productos
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
    SET MESSAGE_TEXT = 'Use UPDATE SET activo = FALSE en lugar de DELETE';
END //
 
DELIMITER ;

Validar relaciones

DELIMITER //
 
CREATE TRIGGER tr_clientes_before_delete
BEFORE DELETE ON clientes
FOR EACH ROW
BEGIN
    DECLARE v_pedidos_activos INT;
 
    SELECT COUNT(*) INTO v_pedidos_activos
    FROM pedidos
    WHERE cliente_id = OLD.id
    AND estado IN ('pendiente', 'enviado');
 
    IF v_pedidos_activos > 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'No se puede eliminar un cliente con pedidos activos';
    END IF;
END //
 
DELIMITER ;

Limpieza

DROP TRIGGER IF EXISTS tr_productos_before_delete;
DROP TRIGGER IF EXISTS tr_archivar_producto;
DROP TRIGGER IF EXISTS tr_soft_delete;
DROP TRIGGER IF EXISTS tr_clientes_before_delete;
DROP TABLE IF EXISTS productos_archivados;

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

Escrito por Eduardo Lázaro