Make column default a query

Posted on

Question :

Is there a way I can set up a column in PostgreSQL 9.2 such that the default value is a query? I am having to track down query statements from different sources that don’t respect the “default” behavior that would like to be seen in the various projects that are writing to the DB.

INSERT INTO Person(name, token, priv, sc)
VALUES ('Frank Josephson', '**fake token**', 'user'
      , (SELECT COUNT(*) FROM Person WHERE name='Frank Josephson'));

Otherwise, it’s just me auditing a bunch of excel sheets and applications to make sure this new directive goes through. Any way to set this up as a trigger without running into race conditions?

Answer :

Here is how you can achieve that using a trigger:

CREATE OR REPLACE FUNCTION default_sc_value()
  RETURNS trigger AS
$BODY$begin
if tg_op='INSERT' then
SELECT COUNT(*) FROM person WHERE name=new.name into new.sc;
end if;

return new;
end;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

and you can associate this trigger to your person table with:

CREATE TRIGGER before_insert_trigger
  BEFORE INSERT
  ON person
  FOR EACH ROW
  EXECUTE PROCEDURE default_sc_value();

Most likely a default value or trigger are not suitable solutions. The values inserted automatically are snapshots and quickly invalidated by subsequent writes to the table.

You should use a VIEW or a “generated column”.

Example for “generated column”

All you need is a function that takes the table type as parameter:

CREATE OR REPLACE FUNCTION sc (person)
  RETURNS bigint AS
$func$
SELECT count(*) FROM person WHERE name = $1.name
$func$ LANGUAGE sql STABLE;

Now, you get the current count with

SELECT *, p.sc
FROM   person p
WHERE  name = 'Frank Josephson';

Details in the related answer on SO:

Maybe try to create a function that returns the value of count(*) and use that in the insert query.

CREATE FUNCTION mycount(personname varchar) RETURNS integer AS $$
declare
retval integer;
begin
SELECT COUNT(*) FROM Person WHERE name=personname into retval;
return retval;
end;
$$ LANGUAGE plpgsql;

then use it in the query:

INSERT INTO Person(name, token, priv, sc)
VALUES ('Frank Josephson', '**fake token**', 'user', mycount('Frank Josephson'))

Leave a Reply

Your email address will not be published. Required fields are marked *