Introducción de PostgreSQL a los Triggers
Los desencadenantes en PostgreSQL son procedimientos especiales que se ejecutan o desencadenan automáticamente cuando se producen determinados eventos en una tabla de la base de datos. Se utilizan para mantener la integridad de los datos, aplicar reglas empresariales y automatizar comprobaciones o transformaciones complejas.
Utilización
Los desencadenantes se emplean para responder automáticamente a eventos como las operaciones `INSERT`, `UPDATE` o `DELETE` en una tabla. Pueden configurarse para que se ejecuten "ANTES", "DESPUÉS" o "ANTES" del evento y, opcionalmente, pueden estar condicionadas a si el evento tiene éxito. Los desencadenantes pueden definirse a nivel de fila, ejecutándose por cada fila afectada, o a nivel de sentencia, ejecutándose una vez por sentencia SQL.
CREATE TRIGGER trigger_name
{ BEFORE | AFTER | INSTEAD OF }
{ INSERT | UPDATE | DELETE }
ON table_name
FOR EACH { ROW | STATEMENT }
EXECUTE FUNCTION function_name();
En esta sintaxis, `CREATE TRIGGER` define un nuevo activador llamado `trigger_name` que llama a una función especificada `function_name` antes, después o en lugar de un evento de modificación de datos en `table_name`.
Los desencadenantes interactúan con comandos de control de transacciones como `COMMIT` y `ROLLBACK`. Si un desencadenante provoca un error, normalmente se anulará toda la transacción, a menos que se gestione explícitamente.
Ejemplos
1. Activador básico de la auditoría
CREATE TABLE audit_log (
id SERIAL PRIMARY KEY,
operation VARCHAR(10),
operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE OR REPLACE FUNCTION log_insert() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log(operation) VALUES ('INSERT');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_audit
AFTER INSERT ON target_table
FOR EACH ROW
EXECUTE FUNCTION log_insert();
Este ejemplo básico registra cada operación de `INSERT` en `tabla_objetivo` en la tabla `registro_auditoría`.
2. Activar con lógica condicional
CREATE OR REPLACE FUNCTION check_salary() RETURNS TRIGGER AS $$
BEGIN
IF NEW.salary < OLD.salary THEN
RAISE EXCEPTION 'Salary cannot be decreased!';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER salary_check
BEFORE UPDATE ON employees
FOR EACH ROW
EXECUTE FUNCTION check_salary();
Este activador garantiza que el salario de un empleado no pueda disminuir durante una operación de actualización.
3. Activador en cascada
CREATE OR REPLACE FUNCTION delete_cascade() RETURNS TRIGGER AS $$
BEGIN
DELETE FROM orders WHERE customer_id = OLD.id;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER cascade_delete
AFTER DELETE ON customers
FOR EACH ROW
EXECUTE FUNCTION delete_cascade();
Este ejemplo borra automáticamente todos los pedidos asociados a un cliente cuando éste es eliminado.
Gestionar desencadenantes
Para desactivar o abandonar un disparador cuando ya no sea necesario, puedes utilizar los siguientes comandos:
ALTER TABLE table_name DISABLE TRIGGER trigger_name;
DROP TRIGGER trigger_name ON table_name;
Para ver los activadores existentes en una base de datos, puedes consultar el catálogo del sistema `pg_trigger`.
Consejos y buenas prácticas
- Haz que los activadores sean sencillos. Una lógica compleja puede provocar cuellos de botella en el rendimiento y problemas de mantenimiento.
- Prueba a fondo. Asegúrate de que tus activadores funcionan como esperas probándolos en varios escenarios.
- Activadores de documentos. Documenta claramente la finalidad y el funcionamiento de cada activador para ayudar a futuros programadores.
- Considera los permisos. Asegúrate de que los usuarios que activan los eventos tienen los permisos adecuados para ejecutar las funciones asociadas.
- Controla el impacto en el rendimiento. Ten en cuenta que el uso extensivo de activadores puede afectar al rendimiento, especialmente en tablas con muchas transacciones.
- Evita los activadores recursivos. Los activadores recursivos pueden dar lugar a bucles infinitos y deben manejarse con precaución.