CREATE TRIGGER orders_auditAFTER INSERT OR UPDATE OR DELETE ON ordersFOR EACH ROW EXECUTE FUNCTION audit_changes();
2. Using BEFORE Triggers
CREATE TRIGGER set_updatedBEFORE UPDATE ON customersFOR EACH ROW EXECUTE FUNCTION touch_updated_at();
Timing
Use Case
BEFORE
Validate / modify NEW row
AFTER
Audit / cascade work
INSTEAD OF
Updatable views only
3. Using AFTER Triggers
CREATE TRIGGER log_ordersAFTER INSERT ON ordersFOR EACH ROW EXECUTE FUNCTION log_new_order();
4. Using INSTEAD OF Triggers
CREATE TRIGGER v_users_insINSTEAD OF INSERT ON v_usersFOR EACH ROW EXECUTE FUNCTION users_ins_handler();
5. Using Row-Level Triggers
CREATE TRIGGER trg FOR EACH ROW ... -- fires per row
6. Using Statement-Level Triggers
CREATE TRIGGER orders_changedAFTER INSERT OR UPDATE OR DELETE ON ordersREFERENCING NEW TABLE AS new_rows OLD TABLE AS old_rowsFOR EACH STATEMENT EXECUTE FUNCTION fan_out();
Granularity
Receives
FOR EACH ROW
NEW, OLD records
FOR EACH STATEMENT
Transition tables (PG 10+)
7. Creating Trigger Function
CREATE FUNCTION touch_updated_at() RETURNS triggerLANGUAGE plpgsql AS $BEGIN NEW.updated_at := now(); RETURN NEW; END $;
8. Using NEW Record
Field
Available
NEW
INSERT, UPDATE (in BEFORE/AFTER row triggers)
OLD
UPDATE, DELETE
9. Using OLD Record
IF OLD.status <> NEW.status THEN INSERT INTO status_log VALUES(NEW.id, OLD.status, NEW.status, now());END IF;
10. Using TG_OP Variable
IF TG_OP = 'DELETE' THEN ... RETURN OLD;ELSIF TG_OP = 'INSERT' THEN ... RETURN NEW;ELSE ... RETURN NEW;END IF;
11. Using TG_WHEN Variable
Special Var
Value
TG_WHEN
'BEFORE' / 'AFTER' / 'INSTEAD OF'
TG_LEVEL
'ROW' / 'STATEMENT'
TG_NAME
Trigger name
TG_NARGS / TG_ARGV[]
Args passed via CREATE TRIGGER
12. Using TG_TABLE_NAME Variable
RAISE NOTICE 'fired on %.%', TG_TABLE_SCHEMA, TG_TABLE_NAME;
13. Using WHEN Condition
CREATE TRIGGER paid_onlyAFTER UPDATE OF status ON ordersFOR EACH ROW WHEN (OLD.status <> 'paid' AND NEW.status = 'paid')EXECUTE FUNCTION on_payment();
14. Returning Values from Triggers
Trigger Type
Return
BEFORE row INSERT/UPDATE
NEW (or modified NEW); NULL to skip
BEFORE row DELETE
OLD; NULL to skip
AFTER row
Return value ignored
Statement-level
NULL
15. Listing Triggers
SELECT tgname, tgrelid::regclass, tgtype, tgenabled FROM pg_trigger WHERE NOT tgisinternal;\d+ orders -- shows triggers