CREATE TRIGGER

On this page Carat arrow pointing down

The CREATE TRIGGER statement defines a trigger on a specified table.

Required privileges

To create a trigger, a user must have the TRIGGER privilege on the table and the EXECUTE privilege on the trigger function. By default, the public role has EXECUTE privilege on all functions, so this is granted automatically unless it has been revoked.

Synopsis

CREATE TRIGGER trigger_create_name BEFORE AFTER INSERT DELETE UPDATE OR ON table_name FOR EACH ROW WHEN a_expr EXECUTE FUNCTION func_name ( trigger_func_args )

Parameters

Parameter Description
trigger_create_name The name of the trigger.
table_name The name of the table associated with the trigger.
func_name The trigger function that is executed when the trigger activates.
a_expr Boolean condition that determines if the trigger function should execute for a given row. For details, refer to Trigger conditions.
trigger_func_args A comma-separated list of constant string arguments.

Examples

The following are examples of basic triggers. For more detailed examples of trigger usage, see Triggers.

Create a BEFORE trigger

Create a sample table:

icon/buttons/copy
CREATE TABLE lock_table (
    id INT PRIMARY KEY,
    name TEXT NOT NULL,
    is_locked BOOLEAN DEFAULT FALSE
);

Populate lock_table with sample values:

icon/buttons/copy
INSERT INTO lock_table VALUES (1, 'Record 1', FALSE);
INSERT INTO lock_table VALUES (2, 'Record 2', TRUE);

Create a trigger function that prevents "locked" rows from being deleted:

icon/buttons/copy
CREATE OR REPLACE FUNCTION prevent_delete_locked()
RETURNS TRIGGER AS $$
BEGIN
  IF (OLD).is_locked THEN
    RAISE EXCEPTION 'Record is locked and cannot be deleted';
  END IF;
  RETURN OLD;
END;
$$ LANGUAGE PLpgSQL;

Create a trigger that executes prevent_delete_locked before a DELETE is issued on lock_table:

icon/buttons/copy
CREATE TRIGGER prevent_locked_delete
BEFORE DELETE ON lock_table
FOR EACH ROW
EXECUTE FUNCTION prevent_delete_locked();

Test the trigger by attempting to delete a row:

icon/buttons/copy
DELETE FROM lock_table WHERE id = 2;
ERROR: Record is locked and cannot be deleted
SQLSTATE: P0001

View lock_table to verify that the row was not deleted:

icon/buttons/copy
SELECT * FROM lock_table;
  id |   name   | is_locked
-----+----------+------------
   1 | Record 1 |     f
   2 | Record 2 |     t
(2 rows)

Create an AFTER trigger

Create two sample tables. stock contains a product inventory, and orders_placed contains a list of orders on those products:

icon/buttons/copy
CREATE TABLE stock (
"product_id" STRING PRIMARY KEY,
"quantity_on_hand" INTEGER NOT NULL DEFAULT 1
);
icon/buttons/copy
CREATE TABLE orders_placed (
"product_id" STRING NOT NULL REFERENCES stock ("product_id"),
"quantity" INTEGER NOT NULL DEFAULT 1
);

Populate stock with three products each at 1000 count:

icon/buttons/copy
INSERT INTO stock ("product_id", "quantity_on_hand") VALUES ('a', 1000), ('b', 1000), ('c', 1000);

Create a trigger function that updates the stock table to reflect the quantity on hand after each order that is placed:

icon/buttons/copy
CREATE OR REPLACE FUNCTION update_stock_after_order()
RETURNS TRIGGER
AS $$
BEGIN
  UPDATE stock
  SET quantity_on_hand = quantity_on_hand - (NEW).quantity
  WHERE stock.product_id = (NEW).product_id;
  RETURN NULL;
END;
$$ LANGUAGE PLpgSQL;

Create a trigger that executes update_stock_after_order after an INSERT is issued on orders_placed (i.e., an order is placed):

icon/buttons/copy
CREATE TRIGGER trg_update_stock_after_order
AFTER INSERT ON orders_placed
FOR EACH ROW
EXECUTE FUNCTION update_stock_after_order();

Test the trigger by inserting some sample orders:

icon/buttons/copy
INSERT INTO orders_placed (product_id, quantity) VALUES ('a', 1), ('b', 3);

View the stock table to see that the quantities have decreased accordingly:

icon/buttons/copy
SELECT * FROM stock;
  product_id | quantity_on_hand
-------------+-------------------
  a          |              999
  b          |              997
  c          |             1000
(3 rows)

See also

×