0

描述:

  • 我在跑步postgresql 13
  • 我有两个不同架构下的表,t1并且t2.
  • t2从某种意义上t1说,它们共享所有相同的列和数据,但t2始终处于t1有效性的下游。
  • 两个表中的行共享相同的主键,我假设这将用作它们之间的链接。

问:

  • 我想创建一个触发器来反映任何变化t1并且同步t2是相同的。
  • 我从INSERTor开始UPDATE,但如果DELETE很容易添加,我也想实现它。

触发代码:

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

当我执行此代码并对 进行测试UPDATEt1,同一行t2不会反映更改或给我任何错误。

我试过了:

  • 离散地将所有行标记为使用NEW.格式更新,但遇到主键列不可编辑的问题t2
  • WHERE在子句之后添加一个子句VALUES,类似于WHERE primary_key=NEW.primary_key,但出现错误。
  • 我看到的另一个选择是IF在 之前添加一个语句 INSERT,或者WHEN在触发器中添加一个子句,但都没有奏效。
4

2 回答 2

2

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

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; 
    
于 2022-01-05T20:06:27.257 回答
1

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

更新行时您可能会遇到错误,t1因为您的触发器函数尝试插入一个新行,t2t2它被插入时,它已经被同一个触发器函数插入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)引用的外键可能会以更简单有效的方式提供您的预期结果,请参阅手册。在这种情况下,您不再需要 triggers和,但仍然需要 trigger 。t1 (col1, col2, col3)ON UPDATE CASCADE ON DELETE CASCADEON UPDATEON DELETEON INSERT

于 2022-01-05T19:43:13.197 回答