postgres update a date field when a boolean field is set to true
-
05-07-2019 - |
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 fals
e, 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.
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
.