PostgreSQL Triggers

Triggers in PostgreSQL are special functions that automatically execute in response to certain events on a table. They help automate tasks, enforce rules, and maintain data integrity without requiring manual intervention.

1. Trigger Components

  • Trigger Event: The operation that activates the trigger (INSERT, UPDATE, DELETE).
  • Trigger Timing: Specifies when the trigger executes (BEFORE, AFTER, INSTEAD OF).
  • Trigger Function: A function that contains the logic to execute when the trigger fires.

2. Creating a Simple Trigger

-- Step 1: Create a trigger function
            CREATE OR REPLACE FUNCTION log_employee_insert()
            RETURNS TRIGGER AS $$
            BEGIN
                INSERT INTO employee_logs(employee_id, action, log_time)
                VALUES(NEW.id, 'INSERT', NOW());
                RETURN NEW;
            END;
            $$ LANGUAGE plpgsql;

            -- Step 2: Create the trigger
            CREATE TRIGGER after_employee_insert
            AFTER INSERT ON employees
            FOR EACH ROW
            EXECUTE FUNCTION log_employee_insert();

3. BEFORE vs AFTER Triggers

  • BEFORE: Executes before the triggering operation. Can modify the data before insert/update/delete.
  • AFTER: Executes after the operation. Commonly used for logging and auditing.

4. Row-Level vs Statement-Level Triggers

  • Row-Level: Executes once for each affected row. Use FOR EACH ROW.
  • Statement-Level: Executes once per SQL statement, regardless of how many rows are affected. Use FOR EACH STATEMENT.

5. Trigger Example: Automatic Timestamp

-- Create function to update modified_at timestamp
            CREATE OR REPLACE FUNCTION update_modified_timestamp()
            RETURNS TRIGGER AS $$
            BEGIN
                NEW.modified_at = NOW();
                RETURN NEW;
            END;
            $$ LANGUAGE plpgsql;

            -- Attach trigger BEFORE UPDATE
            CREATE TRIGGER set_modified_at
            BEFORE UPDATE ON employees
            FOR EACH ROW
            EXECUTE FUNCTION update_modified_timestamp();

6. INSTEAD OF Triggers

INSTEAD OF triggers are mainly used on views to perform operations that the view itself cannot directly execute.

-- Create a view
            CREATE VIEW active_employees AS
            SELECT id, name, department_id, salary
            FROM employees
            WHERE status = 'active';

            -- Create trigger function for the view
            CREATE OR REPLACE FUNCTION insert_active_employee()
            RETURNS TRIGGER AS $$
            BEGIN
                INSERT INTO employees(id, name, department_id, salary, status)
                VALUES (NEW.id, NEW.name, NEW.department_id, NEW.salary, 'active');
                RETURN NEW;
            END;
            $$ LANGUAGE plpgsql;

            -- Attach INSTEAD OF trigger
            CREATE TRIGGER insert_on_active_employees
            INSTEAD OF INSERT ON active_employees
            FOR EACH ROW
            EXECUTE FUNCTION insert_active_employee();

7. Dropping a Trigger

-- Drop a trigger
            DROP TRIGGER IF EXISTS after_employee_insert ON employees;

            -- Drop trigger function
            DROP FUNCTION IF EXISTS log_employee_insert();

8. Best Practices

  • Keep trigger logic simple and efficient to avoid performance bottlenecks.
  • Use triggers for auditing, automatic updates, and enforcing complex constraints.
  • Be careful with cascading triggers to prevent infinite loops.
  • Document triggers clearly, especially when multiple triggers exist on the same table.
  • Test triggers thoroughly in development before deploying to production.

Conclusion

Triggers in PostgreSQL are a powerful feature to automate tasks and enforce business rules. By using BEFORE, AFTER, INSTEAD OF triggers along with row-level and statement-level options, you can maintain data integrity and streamline database operations. In the next tutorial, we will explore Stored Procedures, which allow reusable batch operations and more complex logic.