Creating and Managing Triggers
1. Creating Trigger
CREATE TRIGGER orders_audit
AFTER INSERT OR UPDATE OR DELETE ON orders
FOR EACH ROW EXECUTE FUNCTION audit_changes();
2. Using BEFORE Triggers
CREATE TRIGGER set_updated
BEFORE UPDATE ON customers
FOR 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_orders
AFTER INSERT ON orders
FOR EACH ROW EXECUTE FUNCTION log_new_order();
4. Using INSTEAD OF Triggers
CREATE TRIGGER v_users_ins
INSTEAD OF INSERT ON v_users
FOR 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_changed
AFTER INSERT OR UPDATE OR DELETE ON orders
REFERENCING NEW TABLE AS new_rows OLD TABLE AS old_rows
FOR 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 trigger
LANGUAGE 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_only
AFTER UPDATE OF status ON orders
FOR 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