postgresqltriggerspostgresql-triggers

Postgres Trigger to INSERT UPDATE DELETE on similar derivative table


Description:

The ask:

Trigger Code:

-- Trigger for t1 to t2 --

CREATE OR REPLACE FUNCTION t1_schema.sync_trigger()

RETURNS TRIGGER AS

$$
BEGIN
    INSERT INTO t2_schema.t2 (col1, col2, col3)
    VALUES (NEW.col1, NEW.col2, NEW.col3);
    RETURN NEW;
END
$$ LANGUAGE plpgsql;
    
    
CREATE TRIGGER t1t2_test_sync
AFTER INSERT OR UPDATE ON t1_schema.t1
FOR EACH ROW
EXECUTE PROCEDURE t1_schema.sync_trigger()

When I execute this code and do a test UPDATE on t1, the same row on t2 does not reflect the changes or give me any errors.

I have tried:


Solution

  • (A) Solution based on triggers

    You maybe get an error when updating a row in t1 because your trigger function tries to insert a new row in t2 which has alreday been inserted in t2 by the same trigger function when it has been inserted in t1. You need to duplicate and specialize your trigger functions, one for insert, one for update, one for delete because the treatment to be triggered on t2 is different :

    CREATE OR REPLACE FUNCTION t1_schema.sync_trigger_insert()
    RETURNS TRIGGER AS
    $$
    BEGIN
        INSERT INTO t2_schema.t2 (col1, col2, col3)
        VALUES (NEW.col1, NEW.col2, NEW.col3);
        RETURN NEW;
    END
    $$ LANGUAGE plpgsql;
        
    CREATE TRIGGER t1t2_test_sync_insert
    AFTER INSERT ON t1_schema.t1
    FOR EACH ROW EXECUTE PROCEDURE t1_schema.sync_trigger_insert() ;
    
    CREATE OR REPLACE FUNCTION t1_schema.sync_trigger_update()
    RETURNS TRIGGER AS
    $$
    BEGIN
        UPDATE t2
           SET col1 = NEW.col1
             , col2 = NEW.col2
             , col3 = NEW.col3
         WHERE primary_key_t2 = NEW. primary_key_t1 ; -- primary_key_t2 must be replaced by the set of columns which are in the primary key of t2 with AND operators, the same for NEW.primary_key_t1
        RETURN NEW;
    END
    $$ LANGUAGE plpgsql;
        
    CREATE TRIGGER t1t2_test_sync_update
    AFTER UPDATE ON t1_schema.t1
    FOR EACH ROW EXECUTE PROCEDURE t1_schema.sync_trigger_update() ;
    
    CREATE OR REPLACE FUNCTION t1_schema.sync_trigger_delete()
    RETURNS TRIGGER AS
    $$
    BEGIN
        DELETE FROM t2
         WHERE primary_key_t2 = NEW. primary_key_t1 ; -- primary_key_t2 must be replaced by the set of columns which are in the primary key of t2 with AND operators, the same for NEW.primary_key_t1
        RETURN OLD; -- NEW is not available for triggers ON DELETE
    END
    $$ LANGUAGE plpgsql;
        
    CREATE TRIGGER t1t2_test_sync_delete
    AFTER DELETE ON t1_schema.t1
    FOR EACH ROW EXECUTE PROCEDURE t1_schema.sync_trigger_delete() ;
    

    (B) Solution based on foreign key

    It is possible that a foreign key on t2 (col1,col2,col3) referencing t1 (col1, col2, col3) with the options ON UPDATE CASCADE ON DELETE CASCADE may deliver your expected result in a much more simple and efficient way, see the manual. In this case, you don't need the triggers ON UPDATE and ON DELETE anymore, but you still need the trigger ON INSERT.