Search code examples
sqlpostgresqltriggerssql-updatealter-table

POSTGRESQL Trigger that updates a column after having altered the table


I have a populated table that already has some specific columns. I'd like to alter the table structure by adding a new column which will represent a field that is the count of the rows of another table.

Is it possible to implement it through a trigger in order to do it automatically after the alter command? I have come up with something like this but apparently doesn't update the column:

Function for the trigger:

CREATE FUNCTION update_column() RETURNS TRIGGER AS
$BODY$
DECLARE
num INTEGER;
BEGIN
    SELECT COUNT(*) INTO num FROM mytable1, mytable2 WHERE mytable1.field = mytable2.field GROUP BY mytable1.field;
    UPDATE mytable1 SET new_column = num;
END;
$BODY$
LANGUAGE PLPGSQL;

The trigger:

CREATE TRIGGER insert
AFTER UPDATE
ON mytable1
FOR EACH ROW
EXECUTE PROCEDURE update_column();

And the alter command:

ALTER TABLE mytable1 ADD new_column INT;

Solution

  • Is it possible to implement it through a trigger in order to do it automatically after the alter command?

    Firstly, your trigger fires after each update on the table, not after the alter table. Second, there would not be much point for a trigger on such DDL event anyway.

    If your table has data already, you might need to initialize the column after its creation, with something like:

    update mytable1 t1
    set new_column = (select count(*) from mytable2 t2 where t2.field = t1.field)
    

    As for the logic you wanted in the trigger: you need to use new and old to refer to the row that was changed in the original table - and, typically, you would expect the update to affect either no rows (if field was not changed), or two rows (if it was):

    update mytable1 t1
    set new_column = (select count(*) from mytable2 t2 where t2.field = t1.field)
    where t1.field in (new.field, old.field) and new.field <> old.field
    

    That said, I would not recommend such set up. Maintaining such derived information is expensive and tedious (you have an update trigger, now you need an insert and a delete trigger too). Instead, you can compute the logic on the fly when needed, or create a view:

    create view myview as
    select t1.*, 
        (select count(*) from mytable2 t2 where t2.field = t1.field) as new_column
    from mytable1 t1