Question

For the sake of the example, consider a table

create table foo (
  contents text NOT NULL,
  is_active boolean NOT NULL DEFAULT false,
  dt_active date
)

I insert a record:

insert into foo (contents) values ('bar')

So far, so good. Later on, I now want to 'activate' the record:

update foo set is_active = true

What I would like to do when is_active is changed from false to true, is for dt_active is set to now(). For bonus points it would be nice if is_active is changed from true to false, dt_active is set to null, but I can live without that.

I'd really like to push this housekeeping into the database, it would make the client code much cleaner (since many tables (and even column tuples within tables) could benefit from this technique).

I'm stumped as to how to pull out the current record in the database in the trigger (I'm using plpgsql), in order to compare the "then" with the "now". Pointers to code examples or snippets greatly appreciated.

Was it helpful?

Solution

CREATE OR REPLACE FUNCTION trg_update_foo() RETURNS TRIGGER AS
$BODY$
BEGIN
    IF OLD.is_active = false AND NEW.is_active = true THEN
        NEW.dt_active := now();
    ELSIF OLD.is_active = true AND NEW.is_active = false THEN
        NEW.dt_active := NULL;
    END IF;
    RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql';
CREATE TRIGGER trg_update_foo BEFORE UPDATE ON foo FOR EACH ROW EXECUTE PROCEDURE trg_update_foo();

Should work. For more information, check pl/PgSQL Triggers manual, and for extra points - whole plPgSQL docs.

OTHER TIPS

Inside your plpgsql trigger procedure you have access to some special record-type variables called NEW and OLD that are created for you.

In an UPDATE or INSERT trigger , NEW will represent the record of the new database row.

In an UPDATE or DELETE trigger , OLD will represent the value of the original database row.

In other statement contexts, these record variables will be NULL.

Therefore, it seems like you need to create an INSERT OR UPDATE trigger that looks at the values of OLD.is_active and NEW.is_active.

Here's the documentation page - http://www.postgresql.org/docs/8.1/interactive/plpgsql-trigger.html This page contains sample code for plpgsql that uses NEW and OLD

Have you tried the manual?

Every trigger function has some automatic variables. In case of update triggers the old rows values are accessable via OLD and the changed values via NEW

You can simply check the column value of OLD by OLD.is_active. The same way you can change the values to be put in the database like NEW.dt_active := now();

Hope this hels.

CREATE FUNCTION actrigger() RETURNS TRIGGER AS $$ BEGIN
    IF TG_OP='UPDATE' THEN
        IF NEW.is_active THEN
            IF NOT OLD.is_active THEN
                NEW.dt_active := current_date;
            END IF;
        ELSIF NEW.dt_active IS NOT NULL
            NEW.dt_active := NULL;
        END IF;
    END IF;
    RETURN NEW;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER foobefore BEFORE UPDATE ON foo FORR EACH ROW
    EXECUTE PROCEDURE actrigger();

And you can take care of INSERT too which would be pretty similar except for it shouldn't refer to OLD.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top