Sling Academy
Home/PostgreSQL/How to create a trigger in PostgreSQL

How to create a trigger in PostgreSQL

Last updated: January 05, 2024

Introduction

Triggers in PostgreSQL are powerful tools that allow developers to define functions to be automatically executed before or after changes to the database. This tutorial will guide you through the creation of basic to advanced triggers in PostgreSQL.

Understanding Triggers

Before diving into creating a trigger, let’s define what triggers are and why they’re useful. A trigger is a database object tied to a table—it’s a piece of code that automatically runs in response to specific events on that table, such as INSERT, UPDATE, or DELETE operations. They can be used for auditing, enforcing business rules, maintaining complex integrity constraints, and more.

Creating a Basic Trigger

Let’s start by creating a simple trigger that logs each new row added to a table. First, we need a table:

CREATE TABLE user_audit (
    audit_id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    action TEXT NOT NULL,
    action_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Next, we define a trigger function:

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

Now, we create a trigger that calls this function on each insert:

CREATE TRIGGER user_update_trigger
AFTER INSERT ON users
FOR EACH ROW EXECUTE FUNCTION log_user_update();

Conditional Triggers

You can make triggers conditional based on given criteria. For example, you can define a trigger to run only when a certain column is updated:

CREATE TRIGGER user_update_age_trigger
AFTER UPDATE OF age ON users
FOR EACH ROW
WHEN (OLD.age != NEW.age)
EXECUTE FUNCTION log_user_update();

Modifying Data with Triggers

Triggers in PostgreSQL can also modify the data being inserted, updated, or deleted. Below is an example of a BEFORE trigger that automatically capitalizes names before they are inserted into the database:

CREATE OR REPLACE FUNCTION capitalize_names()
RETURNS TRIGGER AS $
BEGIN
    NEW.name := UPPER(NEW.name);
    RETURN NEW;
END;
$ LANGUAGE plpgsql;

CREATE TRIGGER before_insert_user_trigger
BEFORE INSERT ON users
FOR EACH ROW EXECUTE FUNCTION capitalize_names();

Partitioning Data with Triggers

Triggers can help with table partitioning by redirecting an insert to the correct partition:

CREATE OR REPLACE FUNCTION insert_partition_trigger()
RETURNS TRIGGER AS $
BEGIN
    IF (NEW.log_date >= '2021-01-01' AND NEW.log_date < '2022-01-01') THEN
        INSERT INTO logs_2021 VALUES (NEW.*);
    ELSIF (NEW.log_date >= '2022-01-01' AND NEW.log_date < '2023-01-01') THEN
        INSERT INTO logs_2022 VALUES (NEW.*);
    -- Add more partitions as necessary
    END IF;
    RETURN NULL;
END;
$ LANGUAGE plpgsql;

-- Trigger that redirects to the proper table partition
CREATE TRIGGER partition_insert_trigger
BEFORE INSERT ON logs
FOR EACH ROW EXECUTE FUNCTION insert_partition_trigger();

Advanced Trigger Concepts

Beyond basic usage, PostgreSQL triggers can involve more complex logic. This might include error handling with EXCEPTION blocks, handling transaction statements within a trigger, or leveraging session information to enforce row-level security.

Trigger Limitations and Performance Concerns

Keep in mind that triggers add overhead to transactions, which can affect performance, particularly when bulk loading data or when used on tables with very high write volumes. Unintended recursion can also occur if triggers cause other triggers to fire. Careful planning and understanding of the event trigger chain are essential.

Testing Your Triggers

Safety checks are an important part of trigger creation. After creating a trigger, you should thoroughly test it to ensure that it performs as expected and does not introduce any regressions or unwanted behavior.

Managing Triggers

It’s important to be able to manage your triggers. PostgreSQL offers several commands for this:

-- Disable a trigger
ALTER TABLE users DISABLE TRIGGER user_update_trigger;

-- Enable a trigger
ALTER TABLE users ENABLE TRIGGER user_update_trigger;

-- Drop a trigger
DROP TRIGGER IF EXISTS user_update_trigger ON users;

Conclusion

In this tutorial, we explored how to create triggers in PostgreSQL from simple loggers to complex partitioning schemes. Remember, triggers are powerful but must be used wisely to ensure they do not become a maintenance headache or a performance bottleneck. With the right practices, they can be an invaluable asset to your database arsenal.

Next Article: How to audit data with triggers in PostgreSQL

Previous Article: How to create and use a cursor in PostgreSQL

Series: PostgreSQL Tutorials: From Basic to Advanced

PostgreSQL

You May Also Like

  • PostgreSQL with TimescaleDB: Querying Time-Series Data with SQL
  • PostgreSQL Full-Text Search with Boolean Operators
  • Filtering Stop Words in PostgreSQL Full-Text Search
  • PostgreSQL command-line cheat sheet
  • How to Perform Efficient Rolling Aggregations with TimescaleDB
  • PostgreSQL with TimescaleDB: Migrating from Traditional Relational Models
  • Best Practices for Maintaining PostgreSQL and TimescaleDB Databases
  • PostgreSQL with TimescaleDB: Building a High-Performance Analytics Engine
  • Integrating PostgreSQL and TimescaleDB with Machine Learning Models
  • PostgreSQL with TimescaleDB: Implementing Temporal Data Analysis
  • Combining PostgreSQL, TimescaleDB, and Airflow for Data Workflows
  • PostgreSQL with TimescaleDB: Visualizing Real-Time Data with Superset
  • Using PostgreSQL with TimescaleDB for Energy Consumption Analysis
  • PostgreSQL with TimescaleDB: How to Query Massive Datasets Efficiently
  • Best Practices for Writing Time-Series Queries in PostgreSQL with TimescaleDB
  • PostgreSQL with TimescaleDB: Implementing Batch Data Processing
  • Using PostgreSQL with TimescaleDB for Network Traffic Analysis
  • PostgreSQL with TimescaleDB: Troubleshooting Common Performance Issues
  • Building an IoT Data Pipeline with PostgreSQL and TimescaleDB