Using Conditional Triggers in PostgreSQL

Updated: January 5, 2024 By: Guest Contributor Post a comment

Overview

PostgreSQL’s support for conditional triggers allows for fine-tuned data management and workflow automation, essential for complex database systems. This guide will explore how to use these triggers from simple demonstrations to advanced use cases.

Introduction to Triggers

Before we dive into conditional triggers, let’s understand what triggers are. A trigger in PostgreSQL is a function invoked automatically upon certain events on a database table, like INSERT, UPDATE, or DELETE actions.

CREATE TRIGGER example_trigger
AFTER INSERT ON example_table
FOR EACH ROW
EXECUTE FUNCTION example_function();

The above SQL command establishes a simple trigger that runs after a row is inserted into ‘example_table’.

Conditional Triggers in Action

Unlike standard triggers, conditional triggers execute only when specified conditions are met. This is achieved using the ‘WHEN’ clause.

CREATE TRIGGER example_conditional_trigger
AFTER INSERT ON example_table
FOR EACH ROW
WHEN (NEW.column1 > 100)
EXECUTE FUNCTION example_function();

In this example, ‘example_function()’ is executed only when the inserted row’s ‘column1’ value is greater than 100.

Creating a Basic Trigger Function

To use a trigger, first, we need to define a trigger function. Below is an example of a simple trigger function that logs the action to a table.

CREATE OR REPLACE FUNCTION log_trigger()
RETURNS TRIGGER AS $
BEGIN
    INSERT INTO log_table(event_type, table_name, affected_row)
    VALUES (TG_OP, TG_TABLE_NAME, row_to_json(NEW));
    RETURN NEW;
END;
$ LANGUAGE plpgsql;

This function logs the operation type (TG_OP) and the affected row into a ‘log_table’.

Advanced Trigger Conditions

We can use PostgreSQL’s IF statements within a trigger function for complex conditions.

CREATE OR REPLACE FUNCTION advanced_conditional_function()
RETURNS TRIGGER AS $
BEGIN
    IF (NEW.column1 > 100 AND NEW.column2 <> 'admin') THEN
        -- Triggered action
    END IF;
    RETURN NEW;
END;
$ LANGUAGE plpgsql;

CREATE TRIGGER advanced_conditional_trigger
AFTER INSERT ON example_table
FOR EACH ROW
EXECUTE FUNCTION advanced_conditional_function();

In the above code, the trigger checks if ‘column1’ is greater than 100 and ‘column2’ is not equal to ‘admin’ before proceeding with the triggered action.

Using Triggers for Data Integrity

Conditional triggers can enforce data integrity constraints that are too complex for standard constraints.

CREATE OR REPLACE FUNCTION enforce_data_integrity()
RETURNS TRIGGER AS $
BEGIN
    IF (TG_OP = 'UPDATE' AND OLD.amount <> NEW.amount) THEN
        RAISE EXCEPTION 'Direct modification of the amount is not allowed.';
    END IF;
    RETURN NEW;
END;
$ LANGUAGE plpgsql;

CREATE TRIGGER prevent_amount_change
BEFORE UPDATE ON financials
FOR EACH ROW
WHEN (OLD.amount IS DISTINCT FROM NEW.amount)
EXECUTE FUNCTION enforce_data_integrity();

This function raises an exception if an UPDATE attempt is made on the ‘amount’ column in the ‘financials’ table, preserving the original data.

Dynamic Trigger Assignment

Sometimes, you might need to apply the same conditional logic to multiple tables. PostgreSQL’s event triggers allow you to do just that.

CREATE OR REPLACE FUNCTION dynamic_trigger_function()
RETURNS event_trigger AS $
DECLARE
    object_info json;
BEGIN
    object_info = pg_event_trigger_ddl_commands();
    IF (object_info ->> 'command_tag') = 'CREATE TABLE' THEN
        -- Add a conditional trigger to the newly created table
    END IF;
END;
$ LANGUAGE plpgsql;

CREATE EVENT TRIGGER dynamic_trigger
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE FUNCTION dynamic_trigger_function();

This event trigger dynamically assigns a trigger to every new table created.

Use Case: Audit Logging with Triggers

Triggers are widely used to implement audit logging. By creating a conditional trigger, you can effectively audit changes to sensitive data while ignoring non-critical updates.

CREATE OR REPLACE FUNCTION audit_log_trigger()
RETURNS TRIGGER AS $
BEGIN
    IF (TG_OP = 'DELETE' OR OLD.amount <> NEW.amount) THEN
        INSERT INTO audit_log(user_id, action, table_modified, previous_data, new_data)
        VALUES (current_user, TG_OP, TG_TABLE_NAME, row_to_json(OLD), row_to_json(NEW));
    END IF;
    RETURN NEW;
END;
$ LANGUAGE plpgsql;

CREATE TRIGGER financial_data_audit
AFTER INSERT OR UPDATE OR DELETE ON financials
FOR EACH ROW
EXECUTE FUNCTION audit_log_trigger();

This function creates an audit log entry whenever there’s a DELETE action or when the ‘amount’ column is modified.

Conditional Triggers and Performance

While triggers add powerful functionality, they also introduce additional processing during data manipulation operations. It’s important to ensure they are optimized to prevent performance issues. Always define precise conditions and ensure the trigger function is as streamlined as possible.

Conclusion

PostgreSQL triggers are invaluable tools for maintaining database integrity, automating tasks, and enforcing complex business logic. By understanding how to create and utilize conditional triggers, developers can achieve sophisticated data control with precision and efficiency. Keep triggers efficient and test them thoroughly to ensure they meet the system’s needs without incurring unwanted overhead.