Audit logging helps track changes in your database. A trigger automatically records these changes without manual effort.
Trigger for audit logging in PostgreSQL
Start learning this pattern below
Jump into concepts and practice - no test required
CREATE TRIGGER trigger_name AFTER INSERT OR UPDATE OR DELETE ON table_name FOR EACH ROW EXECUTE FUNCTION function_name();
The trigger runs after data changes (insert, update, delete).
The function called by the trigger contains the audit logic.
CREATE TRIGGER audit_trigger AFTER INSERT ON employees FOR EACH ROW EXECUTE FUNCTION audit_insert();
CREATE TRIGGER audit_trigger AFTER UPDATE OR DELETE ON employees FOR EACH ROW EXECUTE FUNCTION audit_changes();
This example creates an employees table and an audit table. The trigger calls a function that logs inserts, updates, and deletes with old and new names and timestamps.
After running the insert, update, and delete commands, the audit table will show the recorded changes.
CREATE TABLE employees ( id SERIAL PRIMARY KEY, name TEXT NOT NULL, position TEXT NOT NULL ); CREATE TABLE employees_audit ( audit_id SERIAL PRIMARY KEY, employee_id INT, operation TEXT, old_name TEXT, new_name TEXT, changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE OR REPLACE FUNCTION audit_employees_changes() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO employees_audit(employee_id, operation, new_name) VALUES (NEW.id, TG_OP, NEW.name); RETURN NEW; ELSIF TG_OP = 'UPDATE' THEN INSERT INTO employees_audit(employee_id, operation, old_name, new_name) VALUES (NEW.id, TG_OP, OLD.name, NEW.name); RETURN NEW; ELSIF TG_OP = 'DELETE' THEN INSERT INTO employees_audit(employee_id, operation, old_name) VALUES (OLD.id, TG_OP, OLD.name); RETURN OLD; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER audit_employees_trigger AFTER INSERT OR UPDATE OR DELETE ON employees FOR EACH ROW EXECUTE FUNCTION audit_employees_changes(); -- Example insert INSERT INTO employees(name, position) VALUES ('Alice', 'Developer'); -- Example update UPDATE employees SET name = 'Alice Smith' WHERE id = 1; -- Example delete DELETE FROM employees WHERE id = 1; -- Check audit log SELECT * FROM employees_audit;
Make sure the audit table has columns to store old and new values as needed.
Triggers can slow down writes slightly because they run extra code.
Use AFTER triggers to ensure the main operation succeeds before logging.
Triggers automate audit logging by running code on data changes.
Use a trigger function to insert audit records with old and new data.
This helps track who changed what and when in your database.
Practice
Solution
Step 1: Understand what triggers do
Triggers run code automatically when data changes occur in a table.Step 2: Connect triggers to audit logging
Audit logging means recording who changed what and when, which triggers help automate.Final Answer:
To automatically record changes made to data in a table -> Option BQuick Check:
Trigger = automatic audit record [OK]
- Thinking triggers speed up queries
- Confusing triggers with backups
- Assuming triggers create tables
Solution
Step 1: Check function return type and language
Trigger functions must return type 'trigger' and use 'plpgsql' language.Step 2: Verify correct use of OLD and NEW
For audit logging on updates/deletes, OLD.* is used to capture previous data; function returns NEW to continue operation.Final Answer:
CREATE FUNCTION audit_log() RETURNS trigger AS $$ BEGIN INSERT INTO audit_table VALUES (OLD.*); RETURN NEW; END; $$ LANGUAGE plpgsql; -> Option CQuick Check:
Trigger function syntax = CREATE FUNCTION audit_log() RETURNS trigger AS $$ BEGIN INSERT INTO audit_table VALUES (OLD.*); RETURN NEW; END; $$ LANGUAGE plpgsql; [OK]
- Using RETURNS void instead of RETURNS trigger
- Returning OLD instead of NEW
- Wrong language like SQL instead of plpgsql
CREATE FUNCTION audit_func() RETURNS trigger AS $$ BEGIN INSERT INTO audit_log(user_name, action_time) VALUES (current_user, now()); RETURN NEW; END; $$ LANGUAGE plpgsql;
CREATE TRIGGER audit_trigger AFTER INSERT ON employees FOR EACH ROW EXECUTE FUNCTION audit_func();
What happens when a new row is inserted into
employees?Solution
Step 1: Understand AFTER INSERT trigger behavior
AFTER INSERT triggers run after a new row is added, so the insert succeeds first.Step 2: Analyze trigger function actions
The function inserts a row intoaudit_logwith current user and timestamp, logging the event.Final Answer:
A new row is added toaudit_logwith current user and timestamp -> Option AQuick Check:
AFTER INSERT triggers log data after insert [OK]
- Thinking AFTER INSERT prevents insert
- Assuming trigger deletes data
- Believing no action happens after insert
CREATE FUNCTION audit_changes() RETURNS trigger AS $$ BEGIN INSERT INTO audit_log VALUES (NEW.*); RETURN NEW; END; $$ LANGUAGE plpgsql;
But when the trigger fires (e.g., on INSERT or UPDATE to the table), you get an error. What is the likely cause?
Solution
Step 1: Check compatibility of NEW.* with audit_log table
NEW.* expands to all columns of the triggering table, which must match audit_log columns exactly.Step 2: Identify mismatch causes error
If audit_log has different columns or order, the insert fails when the trigger fires.Final Answer:
The audit_log table does not match the NEW record structure -> Option DQuick Check:
Column mismatch causes insert error [OK]
- Thinking RETURN NEW is invalid
- Assuming language must be SQL
- Believing triggers cannot insert data
products table. Which trigger function code correctly captures both old and new data for audit logging?Solution
Step 1: Identify correct use of OLD and NEW in UPDATE triggers
OLD contains previous row data, NEW contains updated data; audit log needs both.Step 2: Check function logic and return value
Insert old and new names correctly, then return NEW to allow update to proceed.Final Answer:
CREATE FUNCTION audit_update() RETURNS trigger AS $$ BEGIN INSERT INTO audit_log(old_name, new_name) VALUES (OLD.name, NEW.name); RETURN NEW; END; $$ LANGUAGE plpgsql; -> Option AQuick Check:
OLD before, NEW after update [OK]
- Swapping OLD and NEW values
- Returning OLD instead of NEW
- Using UPDATE instead of INSERT in audit log
