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();
TimingUse Case
BEFOREValidate / modify NEW row
AFTERAudit / cascade work
INSTEAD OFUpdatable 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();
GranularityReceives
FOR EACH ROWNEW, OLD records
FOR EACH STATEMENTTransition 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

FieldAvailable
NEWINSERT, UPDATE (in BEFORE/AFTER row triggers)
OLDUPDATE, 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 VarValue
TG_WHEN'BEFORE' / 'AFTER' / 'INSTEAD OF'
TG_LEVEL'ROW' / 'STATEMENT'
TG_NAMETrigger 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 TypeReturn
BEFORE row INSERT/UPDATENEW (or modified NEW); NULL to skip
BEFORE row DELETEOLD; NULL to skip
AFTER rowReturn value ignored
Statement-levelNULL

15. Listing Triggers

SELECT tgname, tgrelid::regclass, tgtype, tgenabled
  FROM pg_trigger WHERE NOT tgisinternal;
\d+ orders                       -- shows triggers