3

PostgreSQL default values cannot contain variables or refer to any other columns in the table, or in a different table.

However, is it possible to use a trigger to create a "Default value" that will behave in the following manner. First, let me illustrate with two example tables:

create table projects
(
id serial primary key,
created_at timestamp with time zone default now()
);

create table last_updated
(
project_id integer primary key references projects,
updated_at timestamp with time zone default ...
);

In the second table (last_updated) I would like the default to be something like default projects(created_at). I.e. if a date is not specified for updated_at, look at the project_id referenced in the projects table, find the created_at date, and set the updated_at to this date. However, you cannot write this as per the first paragraph of my question.

So how do you write a trigger that will give this functionality?

2
  • 1
    Presumably, you'd create an insert trigger to check whether NEW.updated_at IS NULL and select the appropriate value from projects into NEW.updated_at if it is, in fact, NULL. Commented May 6, 2015 at 0:56
  • Do note that the sole purpose of such a trigger would be to maintain redundancy. Referring from last_updated.project_id -> projects. created_at would yield the same value; even at a later stage. Commented May 6, 2015 at 10:37

1 Answer 1

1

The correct answer depends on what you do not specify. Typically, one would make updates to the projects table and then audit that in the last_updated table, using an AFTER UPDATE trigger on table projects:

CREATE FUNCTION audit_project_update () RETURNS trigger AS $$
BEGIN
  INSERT INTO last_updated VALUES
    (NEW.id,   -- NEW refers to the updated record in the projects table
     now()     -- this would be the logical value, but can use NEW.created_at
     -- other columns, possibly log session_user
  );
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER tr_projects_update
  AFTER UPDATE ON projects
  FOR EACH ROW EXECUTE PROCEDURE audit_project_update();

Note that in this approach there is never a situation where an INSERT is made on table last_updated without specifying a value for updated_at, assuming that you will not GRANT INSERT to any role on table last_updated, because the trigger function always specifies now(). In the table definition you do not have to specify a default value anymore: the trigger gives you the automated behavior you are looking for.

Your stated question - and confirmed in the comment below - would also use a trigger, but then on the last_updated table:

CREATE FUNCTION project_last_updated () RETURNS trigger AS $$
BEGIN
  IF (NEW.updated_at IS NULL) THEN
    SELECT created_at INTO NEW.updated_at
    FROM projects
    WHERE id = NEW.project_id;
  END IF;
  RETURN NEW;
END; $$ LANGUAGE plpgsql;

CREATE TRIGGER tr_projects_update
  BEFORE INSERT ON last_updated
  FOR EACH ROW EXECUTE PROCEDURE project_last_updated();

This specification begs the question why you do not simply add a column updated_at to the projects table. Since the project_id column is PK in the last_update table, you can only store a single last update date per project.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, this would create an entry in last_updated every time an entry is added to projects, correct? What I would actually like is to be able to manually create an entry in last_updated with a reference to an existing projects.id, and if the last_updated.updated_at field is not specified, to find the created_at date from the projects table and use it as the default.
Thanks, this looks like what I want. To answer your question " begs the question why you do not simply add a column updated_at to the projects table.", the pair of tables is the bare minimum example I could give. The last_updated at table, for example, could be used to generate reports for selected project_ids.

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.