简体   繁体   English

在 Postgres 中使用触发器

[英]Using triggers in Postgres

I have two tables A and B in Postgres DB.我在 Postgres DB 中有两个表 A 和 B。

Whenever I insert a new row or rows in table AI want to add those updates to table B. If table B is empty, all the news rows inserted in table A will be also added to table B. However, when new rows are inserted in table A and if there is already data in table B, I want to delete all those data from table B before performing insert of the new rows of table A into table B.每当我在表 AI 中插入一个或多个新行时,都想将这些更新添加到表 B。如果表 B 为空,则表 A 中插入的所有新闻行也将添加到表 B 中。但是,当在表 B 中插入新行时表A,如果表B中已有数据,我想在将表A的新行插入表B之前从表B中删除所有这些数据。

So basically, every time when new rows are inserted into table A, corresponding rows should also be added to table B but perform delete operation every time before inserting to table B so that there is no old rows in table B. Table B is intended to hold only newly added rows of table A.所以基本上,每次向表A插入新行时,也应该向表B添加相应的行,但每次插入表B之前都要执行删除操作,这样表B中就没有旧行了。表B的目的是仅保存表 A 的新添加行。

Following is the Postgres script where I have used a trigger.以下是我使用触发器的 Postgres 脚本。

    CREATE TRIGGER test_one AFTER INSERT ON A
    FOR EACH ROW EXECUTE PROCEDURE addRows();

    CREATE OR REPLACE FUNCTION addRows() RETURNS TRIGGER AS $remove_table$
       BEGIN
          DELETE from B;
          INSERT INTO B(std_id, name) VALUES (new.col1, new.col2);
          RETURN NEW;
       END;
    $remove_table$ LANGUAGE plpgsql;

This trigger function does the job but not all the newly added rows in table A are preserved.此触发器 function 完成了这项工作,但并未保留表 A 中所有新添加的行。 I end up with only one row in table B that is the last row of newly inserted data in the table A. To reemphasize, if I insert 10 new rows into table A, table B is expected to have 10 rows added.我最终在表 B 中只有一行,这是表 A 中新插入数据的最后一行。再次强调,如果我在表 A 中插入 10 个新行,则表 B 预计将添加 10 行。 However, only the 10th row is added into table B which is not the desired result.但是,只有第 10 行添加到表 B 中,这不是所需的结果。

Can anybody help me understand what's wrong?任何人都可以帮助我了解问题所在吗?

The problem with the trigger is that it fires for each row you insert, not each 'collection' of rows.触发器的问题在于它会为您插入的每一行触发,而不是针对每个“集合”行。 With, for example, a batch of 10 inserts, the trigger will fire 10 times always removing all data in B, leaving you with 1 row - the last to be inserted.例如,使用一批 10 次插入,触发器将触发 10 次,始终删除 B 中的所有数据,留下 1 行 - 最后插入。

Why create this additional table and duplicate data?为什么要创建这个额外的表并重复数据? Could you not store an insert date/time or an 'insert batch number' in table A and either query from this or create a view on it?您是否不能在表 A 中存储插入日期/时间或“插入批号”并从中查询或在其上创建视图?

Since Postgres 10, pseudo tables are supported through which the inserted set can be accessed in FOR EACH STATEMENT triggers.从 Postgres 10 开始,支持伪表,通过这些伪表可以在FOR EACH STATEMENT触发器中访问插入的集合。

Change your function to do an INSERT... SELECT... from such a pseudo table.从这样的伪表中更改您的 function 以执行INSERT... SELECT...

CREATE
 OR REPLACE FUNCTION addrows
                     ()
                     RETURNS TRIGGER
AS
$$
BEGIN
  DELETE FROM b;
  
  INSERT INTO b
              (std_id,
               name)
              SELECT col1,
                     col2
                     FROM inserted;
  RETURN NULL;
END;
$$
LANGUAGE plpgsql;

And when creating the trigger, make it aa FOR EACH STATEMENT trigger and add a reference for the pseudo table.并且在创建触发器时,将其设为FOR EACH STATEMENT触发器并添加对伪表的引用。

CREATE TRIGGER test_one
               AFTER INSERT ON a
               REFERENCING NEW TABLE AS inserted
               FOR EACH STATEMENT
               EXECUTE PROCEDURE addrows();

db<>fiddle db<>小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM