When you are working with triggers it might be important to know in which order they fire. Of course, a “before” triggers fires before an “after” trigger. But what happens if you have two or more triggers for the same event? Maybe you want to make sure that a specific trigger is executed first (for whatever reason) or you want to make sure that another trigger is executed last. The good news is: You can make your triggers fire in the order you want, you just have to know the rules.

Let’s create a simple setup:

postgres=# create table t1 ( a int );
CREATE TABLE
postgres=# insert into t1 values (1),(2),(3);
INSERT 0 3
postgres=# create table t1_order ( a text, b timestamptz );
CREATE TABLE

The first table will be used to attach triggers and the second table will be used to record the timestamp when a trigger fired. This should give as the answer about the order of execution.

Before we can create a trigger in PostgreSQL we need a trigger function, and we’ll create two, as we will create two triggers for the same event:

postgres=# create or replace function a_trg_func()
  returns trigger as
$$
begin
    insert into t1_order values ('a_trg_func', clock_timestamp() );
    return new;
end;
$$ language plpgsql;
CREATE FUNCTION
postgres=# create or replace function b_trg_func()
  returns trigger as
$$
begin
    insert into t1_order values ('b_trg_func', clock_timestamp() );
    return new;
end;
$$ language plpgsql;
CREATE FUNCTION

As you can see, both functions will create a row in the second table, recording the current timestamp. The two triggers:

postgres=# create or replace trigger a_trg
  before update
  on t1
  for each row
  execute procedure a_trg_func();
CREATE TRIGGER
postgres=# create or replace trigger b_trg
  before update
  on t1
  for each row
  execute procedure b_trg_func();
CREATE TRIGGER
postgres=# 

Doing a simple update on the first table will fire both triggers, and we should be able to compare the timestamps:

postgres=# update t1 set a = 5 where a = 1;
UPDATE 1
postgres=# select * from t1_order;
     a      |               b               
------------+-------------------------------
 a_trg_func | 2021-09-15 13:49:26.468139+02
 b_trg_func | 2021-09-15 13:49:26.468324+02
(2 rows)

The “a_trg” trigger was executed first, but maybe this was luck. Lets repeat the test:

postgres=# truncate t1_order;
TRUNCATE TABLE
postgres=# update t1 set a = 8 where a = 5;
UPDATE 1
postgres=# select * from t1_order;
     a      |               b               
------------+-------------------------------
 a_trg_func | 2021-09-15 13:51:09.821264+02
 b_trg_func | 2021-09-15 13:51:09.823611+02
(2 rows)

Same picture, so it seams they are executed in alphabetical order. We can easily confirm this be renaming the “a_trg” trigger and then do the same test again:

postgres=# alter trigger a_trg on t1 rename to z_trg;
ALTER TRIGGER
postgres=# truncate t1_order;
TRUNCATE TABLE
postgres=# update t1 set a = -1 where a = 8;
UPDATE 1
postgres=# select * from t1_order;
     a      |               b               
------------+-------------------------------
 b_trg_func | 2021-09-15 13:53:13.942374+02
 a_trg_func | 2021-09-15 13:53:13.942723+02
(2 rows)

The order of execution switched, so you can force the order of execution by following a naming convention. The documentation is clear about this behavior: “SQL specifies that multiple triggers should be fired in time-of-creation order. PostgreSQL uses name order, which was judged to be more convenient..


Thumbnail [60x60]
by
Daniel Westermann