Postgres 触发器以在类似导数 table 上插入更新删除

Postgres Trigger to INSERT UPDATE DELETE on similar derivative table

描述:

提问:

触发代码:

-- 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()

当我执行此代码并在 t1 上执行测试 UPDATE 时,t2 上的同一行未反映更改或给我任何错误。

我试过:

(A) 基于触发器的解决方案

更新 t1 中的行时可能会出现错误,因为您的触发器函数试图在 t2 中插入新行,而该行已被相同的人插入到 t2 中插入t1时触发函数。您需要复制和专门化您的触发器函数,一个用于插入,一个用于更新,一个用于删除,因为在 t2 上触发的处理方式不同 :

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) 基于外键的解决方案

t2 (col1,col2,col3) 上的外键引用 t1 (col1, col2, col3) 和选项 ON UPDATE CASCADE ON DELETE CASCADE 可能会以更简单有效的方式提供您预期的结果,请参阅 manual。在这种情况下,您不再需要触发器 ON UPDATEON DELETE,但您仍然需要触发器 ON INSERT.

您最好的方法是不要将 t2 创建为table。而是在 t1 上将其创建为 VIEW。这完全消除了使它们保持同步的触发器,因为实际源是相同的。遵循仅在 1 个位置存储单个数据点的概念。请记住,如果您将一件单品存放在 2 个地方,其中 1 个在某些时候会出错。 (参见 demo)。

create view soq2.t2 as 
            select * 
              from soq1.t1;

此外,如果您需要更改列名,请在创建视图期间使用别名;

create view soq2.t2a as 
       select t1_id  as t2_id
            , name   as t2_name 
            , status as t2_status
         from soq1.t1;