Triggers BEFORE, AFTER e INSTEAD OF para validación, auditoría y reacciones transaccionales, con sus riesgos de comportamiento implícito y costo por fila.
Última actualización
Actualizada
Nivel
Profundización
Un trigger garantiza que una reacción ocurra sin importar qué cliente modifica la tabla. Esa fuerza también es su riesgo: introduce comportamiento implícito dentro de cada escritura.
CREATEFUNCTION app.set_updated_at()RETURNStriggerLANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at := clock_timestamp();RETURN NEW;END;
$$;CREATETRIGGER products_set_updated_at
BEFORE UPDATEON app.products
FOR EACH ROWEXECUTEFUNCTION app.set_updated_at();
Un BEFORE puede modificar NEW o devolver NULL para omitir la fila en ciertos contextos. Debe documentarse porque el resultado final puede diferir del SQL enviado.
FOR EACH ROW ejecuta una vez por fila. Un update de un millón de filas invoca un millón de veces.
FOR EACH STATEMENT ejecuta una vez por statement y puede usar transition tables:
SQL
CREATETRIGGER orders_audit
AFTERUPDATEON orders
REFERENCING OLD TABLEAS old_rows NEW TABLEAS new_rows
FOR EACH STATEMENT
EXECUTEFUNCTION audit_orders();
Esto permite procesar conjuntos y evitar lógica row-by-row.
Varios triggers del mismo evento/timing se ejecutan según reglas de nombre. No construyas un workflow frágil basado en nombres alfabéticos; consolida responsabilidades o documenta dependencias.
Un AFTER trigger puede insertar evento outbox en la misma transacción. Ventaja: ningún cliente olvida hacerlo. Coste: el trigger debe conocer el contrato de eventos y aumenta acoplamiento.
No publiques HTTP/Kafka directamente desde el trigger. La llamada externa no revierte y mantiene la transacción esperando.
CREATETRIGGER orders_status_audit
AFTERUPDATEOFstatusON orders
FOR EACH ROWWHEN(OLD.statusISDISTINCTFROM NEW.status)EXECUTEFUNCTION audit_status_change();
Si el trigger falla, falla el statement y normalmente la transacción queda abortada. El cliente debe ver un SQLSTATE útil. Un error genérico del trigger puede hacer difícil diagnosticar la operación original.
La función usa por defecto privilegios del invoker, pero ownership y SECURITY DEFINER pueden cambiarlo. Aplica las mismas reglas de search path seguro. Revoca permisos directos que permitirían saltarse el boundary cuando el trigger es parte de la seguridad.
Los triggers deben formar parte de migraciones versionadas. Durante backfills decide explícitamente si deben ejecutarse; deshabilitarlos puede romper integridad y requiere privilegios altos. Nunca lo hagas como solución improvisada.