72

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?

1
  • Pls note that this value X has to be retrieved from another subquery. Commented Apr 19, 2013 at 10:31

2 Answers 2

121

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 invokes the above function and fires BEFORE INSERT, which allows you to change the incoming values before they hit the table:

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.


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);
Sign up to request clarification or add additional context in comments.

3 Comments

Why are you not using $$ but instead '?
@StefanFalk One possible reason is that software like DbVisualizer has delimiter problems with the $$. I have been deprived of using functions all this time until you pointed that out!
if you dont like the IF, you could use a single line with coalesce() , something like : new.c1 := coalesce (new.c1,X);
12

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));

3 Comments

Thanks, but in my case I get an error when setting the value as default constrain. Because this value X is get by a subquery so it is not allowed. Can you pls tell me a workaround.
Is the value of C1 uniquely determined by the other values in the same row or does it depend on other factors like the time of day or data in other tables?
It is uniquely determined. simply it's retrieved by (select id from Table2 where name = 'Unique_Value'). This id can be different in different DBs, so have to retrieve it always from a subquery.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.