Postgresql insert trigger to set value

Assume in Postgresql, I have a table T and one of its column is C1.

I want to trigger a function when a new record is adding to the table T. The function should check the value of column C1 in the new record and if it is null/empty then set its value to 'X'.

Is this possible?


You are correct that you need a trigger, because setting a default value for the column won't work for you - default values only work for null values and don't help you in preventing blank values.

In postgres there are a couple of steps to creating a trigger:

Step 1: Create a function that returns type trigger:

CREATE FUNCTION my_trigger_function()
RETURNS trigger AS $$
BEGIN
  IF NEW.C1 IS NULL OR NEW.C1 = '' THEN
    NEW.C1 := 'X';
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql

Step 2: Create a trigger that fires before insert, which allows you to change values befre they are inserted, that invokes the above function:

CREATE TRIGGER my_trigger
BEFORE INSERT ON T
FOR EACH ROW
EXECUTE PROCEDURE my_trigger_function()

And you're done.

See the above code executing on SQLFIddle demonstrating it working correctly!


You mention in a comment that the value 'X' is retrieved from a subquery. If so, change the relevant line so something like:

NEW.C1 := (select some_column from some_table where some_condition);

It is possible but you are likely to be better off setting a default constraint on the column instead. When creating the table that would look like:

create table mytable as (
    C1 thetype not null default X
);

This says that if you add a row to the table and don't specify the value for C1 then X will be used instead. The not null is not necessary, but prevents updates from nulling that column assuming that's what you want.

EDIT: This only works for constant X, from your comments it seems there are two possible solutions.

Using a trigger would look something like this:

create function update_row_trigger() returns trigger as $$
begin
    if new.C1 is NULL then
        new.C1 := X;
    end if;
    return new;
end
$$ language plpgsql;

create trigger mytrigger before insert on mytable for each row execute procedure update_row_trigger();

The new variable in a trigger function is special, representing the row being inserted. Specifying the trigger as a before insert trigger means you can modify the row before it is written to the table.

The second solution would be to use a computed column which Postgres defines in an unusual way:

create or replace function C1(row mytable) returns columntype immutable as $$
begin
    return X; -- where X is an expression using values from `row`
end
$$ language plpgsql;

This creates a function that takes a row of your table and returns a value, you can call it using . notation though, meaning you can do:

select
    *,
    t.C1
from
    mytable t;

The declaration of the function being immutable is optional, but it's needed if you want to index the "column". You would be able to index this column like this:

create index on mytable (C1(mytable));