Skip to main content

Procedures Triggers Functions

πŸ”₯ PostgreSQL Summary: Triggers, Functions, and Procedures​

Coming from an MS SQL (BI/DE) background, I instinctively default to stored procs for any non-relational logic. However, in PostgreSQL, functions and triggers are incredibly powerful and often a better fit. So here’s a concise breakdown of triggers, functions, and procedures in PostgreSQL, including when to use each and permission considerations.

πŸ”₯ Summary Table: Triggers vs. Functions vs. Procedures​

FeatureTriggersFunctionsProcedures
PurposeAuto-execute logic on table changesReturn a value from a queryExecute multi-step operations
Called ByINSERT, UPDATE, DELETE eventsSELECT function_name()CALL procedure_name()
ReturnsNothingA value (or table)Nothing
Can Modify Data?βœ… Yes⚠️ Yes (if SECURITY DEFINER)βœ… Yes
Transaction Control?❌ No❌ Noβœ… Yes (COMMIT / ROLLBACK)
Main Use CaseAuditing, enforcing constraintsEncapsulating queriesBatch operations, data migration
Grant PermissionGRANT TRIGGERGRANT EXECUTE ON FUNCTIONGRANT EXECUTE ON PROCEDURE

πŸš€ When to Use Each?​

βœ” Use a TRIGGER when you need automatic actions on table updates (e.g., logging changes).
βœ” Use a FUNCTION when you want to return values or encapsulate queries.
βœ” Use a PROCEDURE when you need multi-step changes inside a single transaction.


πŸ›  1. PostgreSQL Triggers​

πŸ“Œ What Are Triggers?​

  • Triggers are automatic actions executed before or after INSERT, UPDATE, or DELETE operations on a table.
  • They enforce business logic, audit changes, or cascade updates.

πŸ“Œ When to Use?​

βœ” Automatically log changes (audit logs).
βœ” Enforce constraints beyond standard foreign keys.
βœ” Modify data before inserting/updating.

πŸ“Œ Key Permissions​

PrivilegeEffect
TRIGGERAllows creating, modifying, and dropping triggers.
Without TRIGGERUser can only execute existing triggers.

πŸ”₯ Example: Create an Audit Log Trigger​

CREATE TABLE user_audit (
id SERIAL PRIMARY KEY,
user_id UUID,
action TEXT,
changed_at TIMESTAMP DEFAULT now()
);

CREATE OR REPLACE FUNCTION log_user_changes() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO user_audit (user_id, action)
VALUES (NEW.user_id, TG_OP);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER user_trigger
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW EXECUTE FUNCTION log_user_changes();

βœ… Automatically logs inserts, updates, and deletes for users.


πŸ›  2. PostgreSQL Functions​

πŸ“Œ What Are Functions?​

  • Functions return a value (RETURNS something) and are used for calculations, data transformations, and queries.
  • Functions run inside a transaction (safe for SELECT queries).

πŸ“Œ When to Use?​

βœ” Compute derived values (e.g., full_name(first_name, last_name)).
βœ” Encapsulate complex queries for reuse.
βœ” Perform operations inside queries (e.g., formatting).

πŸ“Œ Key Permissions​

PrivilegeEffect
EXECUTEAllows running the function.
Without EXECUTEThe user cannot call the function.

πŸ”₯ Example: Create a Function​

CREATE OR REPLACE FUNCTION get_active_users() RETURNS TABLE(user_id UUID, email TEXT) AS $$
BEGIN
RETURN QUERY SELECT user_id, primary_email FROM users WHERE is_active = TRUE;
END;
$$ LANGUAGE plpgsql;

βœ… Can be used like a table:

SELECT * FROM get_active_users();

Grant Execute Permission​

GRANT EXECUTE ON FUNCTION get_active_users() TO app_user;

βœ… Now app_user can call the function.


πŸ›  3. PostgreSQL Procedures​

πŸ“Œ What Are Procedures?​

  • Procedures (CALL procedure_name()) allow executing multiple SQL statements inside a single transaction.
  • Unlike functions, procedures can commit or roll back transactions.

πŸ“Œ When to Use?​

βœ” Execute multi-step database changes.
βœ” Run batch operations.
βœ” Perform transaction-safe updates.

πŸ“Œ Key Permissions​

PrivilegeEffect
EXECUTEAllows calling the procedure.
Without EXECUTEThe user cannot run it.

πŸ”₯ Example: Create a Procedure​

CREATE OR REPLACE PROCEDURE deactivate_users(days_old INT) AS $$
BEGIN
UPDATE users
SET is_active = FALSE
WHERE last_login < NOW() - INTERVAL '1 day' * days_old;
END;
$$ LANGUAGE plpgsql;

βœ… To call it:

CALL deactivate_users(30);

Grant Execute Permission​

GRANT EXECUTE ON PROCEDURE deactivate_users(INT) TO app_user;

βœ… Now app_user can deactivate old users.