How to Use Triggers in PostgreSQL
Introduction
Triggers in PostgreSQL allow developers to define rules and actions which can be executed without their manual intervention, making database management more efficient. By utilizing triggers in a database, users can create a dynamic and responsive database that responds and adapt to the changes made in the application.
This article walks you through the functionality of triggers in PostgreSQL. It demonstrates the steps to create, alter and drop a trigger function.
Prerequisites
- Deploy a Vultr Managed Database for PostgreSQL.
- Install the
psql
CLI tool on your computer to connect to the database.
How Triggers Work
Trigger functions are called when specific actions such as data modification operations like INSERT
, DROP
, and ALTER
, are called. This allows developers to perform event-driven queries within the database.
The following are the components for creating triggers.
- Trigger Event: Specified by a user to run the trigger function.
- Trigger Condition: Specified by a user before the function is executed.
- Trigger Function: Contains SQL statements to perform the desired action.
Below are some user cases for implementing triggers.
- Maintaining Logs
- Data Transformation
- Adding Timestamps
- Data Validation
- Raise Alerts
- Perform Additional Task
Types of Triggers
Data Definition Langauge (DDL) Triggers
DDL consists of commands such as
CREATE
,DROP
, andALTER
. When DDL commands are called within the trigger function, it's called a DDL Trigger.Data Manipulation Langauge (DML) Triggers
DML consists of commands such as
INSERT
,UPDATE
, andDELETE
. When DML commands are called within the trigger function, it's called a DML Trigger.LOGON Triggers
This consists of the
LOGON
command which is fired before a user session is established. Therefore all the messages defined by the developer, such as error and success messages are redirected to a SQL server as a SQL Server log.
Set up the Database
In this section, set up a new database with a users
table, and users_log
to log changes using a trigger in PostgreSQL as described below.
Log in to your Vultr Managed Database for PostgreSQL.
$ psql -h mydb.postgres.vultr.com -p 5432 -U admin --dbname postgres
Replace
mydb.postgres.vultr.com
,5432
,admin
with your account Vultr Managed Database details.Create a new database named
DB1
.=> CREATE DATABASE DB1;
Switch to the database.
=> \c mydatabase
Create a new
users
table.CREATE TABLE users ( user_id INT, user_name VARCHAR, address VARCHAR );
The
users
table consists of 3 columns,user_id
,user_name
, and theiraddress
. Operations such asinsert
andupdate
will only run in theusers
table, and theusers_log
table consists of similar columns with similar column constraints.Create the
users_log
table.CREATE TABLE users_log ( old_user_id INT, old_user_name VARCHAR, old_address VARCHAR );
Verify that the tables are created.
\d;
Output:
Schema | Name | Type | Owner --------+-----------+-------+---------- public | users | table | postgres public | users_log | table | postgres
Populate data to the
users
table.INSERT INTO public.users VALUES (1, 'john', 'Miami, FL'), (2, 'jane', 'West Palm Beach, FL'), (3, 'jacob', 'Fort Lauderdale, FL');
View the table data.
SELECT * FROM public.users;
Output:
user_id | user_name | address ---------+-----------+----- 1 | john | Miami, FL 2 | jane | West Palm Beach, FL 3 | jacob | Fort Lauderdale, FL
Verify that the
users_log
table has no stored data.SELECT * FROM public.users_log;
Output:
old_user_id | old_user_name | old_address -------------+---------------+------------- (0 rows)
You have created 2 tables named users
and users_log
. You will implement a trigger function to log any changes made in the users
table to the users_log
table.
Create a Trigger Function
In this section create a trigger function using the inbuilt CREATE
SQL operation followed by the keyword FUNCTION
as described below.
Create a trigger function.
CREATE FUNCTION users_log_trg_func() RETURNS TRIGGER LANGUAGE 'plpgsql' AS $$ BEGIN INSERT INTO public.users_log (old_user_id,old_user_name,old_address) VALUES(OLD.user_id,OLD.user_name,OLD.address); RETURN NEW; END; $$;
Below is what the above SQL command does:
CREATE FUNCTION users_log_trg_func() RETURNS TRIGGER LANGUAGE 'plpgsql' AS $$ BEGIN
The function name
users_log_trg_func
is suffixed with()
. There are multiple functions in PostgreSQL and it's necessary to label the function as a trigger andRETURNS TRIGGER
is used for this purpose.plpgsql
represents the assigned procedural language supported by the PostgreSQL Object Relational Database Management System (ORDBMS).$$
acts as a delimiter used when writing a multi-line string literal. Using$$
specifies that anything written after this should be treated as a single string literal. TheBEGIN
operator marks the beginning of the function's main executable block.INSERT INTO public.users_log (old_user_id,old_user_name,old_address) VALUES(OLD.user_id,OLD.user_name,OLD.address);
The above code implements a trigger that uses old data (before performing an update or delete) in the
users
table, and inserts it in theusers_log
table, theOLD
keyword is used to store only old data in the table.RETURN NEW; END; $$;
This ensures that the value of the row after the trigger event has occurred.
END
and$$
ensure that the trigger function's body is concluded without any errors.
Create a Trigger Event
To successfully use a trigger function, create a trigger event as described below.
Create a trigger event.
CREATE TRIGGER users_trig BEFORE DELETE OR UPDATE ON public.users FOR EACH ROW EXECUTE PROCEDURE users_log_trg_func();
Below is what the above SQL statement does:
CREATE TRIGGER users_trig
The
CREATE
operation creates a trigger followed by the keywordTRIGGER
to create a trigger namedusers_trig
.BEFORE DELETE OR UPDATE ON public.users
Specifies the event condition on which the trigger must be called. The trigger must be called before a delete or update event is called on a table. For this article, the
users
table.FOR EACH ROW
Defines when it's required for the trigger functions to run for each row.
EXECUTE PROCEDURE users_log_trg_func();
Links the trigger function to the trigger command.
Output on Executing Trigger Functions
A trigger event is activated when an
UPDATE
orDELETE
command runs. In the following command, the trigger function is called automatically.UPDATE public.users SET user_name='John Doe' WHERE user_id=1;
The above command updates the user id
1
in theusers
table.View the updated
users
table data.SELECT * FROM public.users;
Output:
user_id | user_name | address ---------+-----------+--------------------- 2 | jane | West Palm Beach, FL 3 | jacob | Fort Lauderdale, FL 1 | John Doe | Miami, FL
View the
users_log
table data.SELECT * FROM public.users_log;
Output:
old_user_id | old_user_name | old_address -------------+---------------+------------- 1 | john | Miami, FL
No changes are made manually to the
users_log
table. But, as soon as theUPDATE
command is executed, the trigger function is called to add old data from theusers
table to theusers_log
table. The old username,john
, is now stored in theusers_log
table and the updated nameJohn Doe
is only available in the mainusers
table.Execute another update statement:
UPDATE public.users SET user_name='Jayne Doe' WHERE user_id=2;
The updated
users
table data should be:user_id | user_name | address ---------+-----------+--------------------- 3 | jacob | Fort Lauderdale, FL 1 | John Doe | Miami, FL 2 | Jayne Doe | West Palm Beach, FL
Verify that the
users_log
table has more data from the trigger function.SELECT * FROM public.users_log;
Output:
old_user_id | old_user_name | old_address -------------+---------------+--------------------- 1 | john | Miami, FL 2 | jane | West Palm Beach, FL
This shows that the trigger function is working and it's able log old data to the
users_log
table
Trigger Operations
After creating a trigger function, you can still enable, disable, drop, or alter the function using the following functions.
Disable Trigger
To disable a trigger function, you can use the ALTER TABLE
operation to modify the structure or property of the table. This is followed by the table name, and the DISABLE
keyword which stops the trigger from making any further changes using the syntax below.
ALTER TABLE table_name DISABLE TRIGGER trigger_name;
For example, disable the users
table trigger as below.
ALTER TABLE public.users DISABLE TRIGGER public.users_trig;
Enable Triggers
Similar to disable, you can re-enable the trigger function in case it's disabled using the syntax below.
ALTER TABLE public.users ENABLE TRIGGER public.users_trig;
For example:
ALTER TABLE public.users ENABLE TRIGGER users_trig;
Alter a Trigger
To update a trigger, use the REPLACE
keyword. Other body commands can remain the same as before using the syntax below.
CREATE OR REPLACE FUNCTION function_name()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
-- Updated function body
RETURN NEW;
END;
$$;
For example:
CREATE OR REPLACE FUNCTION users_log_trg_func()
RETURNS TRIGGER
LANGUAGE 'plpgsql'
AS $$
BEGIN
INSERT INTO public.users_log
(old_user_id,old_user_name,old_address)
VALUES(OLD.user_id,OLD.user_name,OLD.address);
RETURN NEW;
END;
$$;
Delete a Trigger
To permanently delete a trigger, you can use the DROP
command. But to avoid any errors, it's a good practice to use IF EXISTS
using the syntax below.
DROP TRIGGER [IF EXISTS] trigger_name ON table_name;
For example:
DROP TRIGGER IF EXISTS users_trig ON users;
Optional Functions
BEGIN and END
These are optional commands that are only used when writing multiple condition lines within a trigger function. It's a good practice to use BEGIN
and END
when writing any new query.
FOR EACH ROW
If FOR EACH ROW
is not specified, the trigger function is executed once irrespective of how many rows are being updated. Using FOR EACH ROW
enables the trigger to run on each predefined row.
WHERE Clause
The WHERE
clause can be used within a trigger function to make sure the trigger is executed only when certain conditions are met. For example:
CREATE FUNCTION users_log_trg_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
-- Insert into users_log only if address is 'Miami, FL'
INSERT INTO users_log (old_user_id, old_user_name, old_address)
SELECT OLD.user_id, OLD.user_name, OLD.address
WHERE OLD.address = 'Miami, FL';
RETURN NEW;
END;
$$;
In the above query, the trigger filters the user address column to return values with Miami, FL
.
RAISE
Raise logs a warning or notice when a trigger function is executed. It's useful for establishing communication while the trigger function is executed.
CREATE FUNCTION users_log_trg_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
IF new.user_name IS NULL THEN
RAISE NOTICE 'User name is missing';
END IF;
RETURN NEW;
END;
$$;
The above query establishes a warning communication when the user_id
is null. If the condition is true, a notice with the text 'User name is missing' is generated. Other variants of the raise function such as RAISE WARNING
or RAISE EXCEPTION
offer different levels of severity
Conclusion
In this article, you implemented the fundamental concepts of triggers in PostgreSQL. You also created a trigger function, and set up trigger events to perform operations on triggers and other advanced configurations. It's important to note that although triggers offer more flexibility, a poorly configured trigger will cause significant performance loss and unwanted complications. Therefore, proper planning and testing of such functions is required to make sure the triggers align with the database requirements.
More Information
For more information, visit the following resources.