2017-04-12 73 views
2

我有一个包含与日常业务数据的两个表:每独特价值执行函数一次

CREATE TABLE main_table (
    main_id serial, 
    cola text, 
    colb text, 
    colc text, 
    CONSTRAINT main_table_pkey PRIMARY KEY (main_id) 
); 

CREATE TABLE second_table (
    second_id serial, 
    main_id integer, 
    cold text, 
    CONSTRAINT second_table_pkey PRIMARY KEY (second_id), 
    CONSTRAINT second_table_fkey FOREIGN KEY (main_id) 
    REFERENCES main_table (main_id) MATCH SIMPLE 
    ON UPDATE NO ACTION ON DELETE NO ACTION 
); 

我们有必要知道一些数据在这些表中进行了更新,使出口可以生成并推到第三方。我创建了一个第三个表来保存更新信息:

CREATE TYPE field AS ENUM ('cola', 'colb', 'colc', 'cold'); 
CREATE TABLE table_updates (
    main_id int, 
    field field 
    updated_on date NOT NULL DEFAULT NOW(), 
    CONSTRAINT table_updates_fkey FOREIGN KEY (main_id) 
    REFERENCES main_table (main_id) MATCH SIMPLE 
    ON UPDATE NO ACTION ON DELETE NO ACTION 
); 

main_table具有触发更新table_updatesUPDATE查询,满足需要跟踪三个四柱更新。

我可以很容易地添加相同类型的触发器来second_table,但是因为main_id不是唯一的功能可以为单个main_id值,这是不希望被执行数次。

如何创建一个函数,在更新second_table中的多个行时,每main_id只执行一次?

回答

2

如何创建一个函数,在更新second_table中的多行时,每个main_id只执行一次?

如果您的刀片通过main_id即批量插入INSERT INTO tbl (main_id...) VALUES (main_id ...),(main_id ...),(main_id ...)可以使用rule systemINSERTUPDATE

对于可通过两种实现的事情,这是最好的取决于触发一次关于数据库的使用。 每个受影响的行触发器触发一次。规则会修改查询或生成其他查询。因此,如果在一条语句中有很多行受到影响,那么发出一条额外命令的规则可能会快于为每一行调用的触发器,并且必须重新确定多次执行的操作。然而,触发器方法在概念上比规则方法简单得多,而且新手更容易获得正确的方法。

害羞的是,你可能还想看看正常的LISTENNOTIFY。哪些给你使用异步操作的能力。如果这是您的事情,并且您决定保留触发方法,请考虑触发更改通知模块,通过tcn

我的建议是在应用程序中(数据库外)如果可能的话这样做。请记住,PostgreSQL temp表是会话本地的。所以,你可以在每个架会议做这样的事情,

BEGIN 
    CREATE TEMP TABLE UNLOGGED etl_inventory; 
    COPY foo FROM stdin; 
    -- Are they different, if so `NOTIFY` 
    -- UPSERT 
COMMIT; 

然后一个有一个守护进程,做出口的附加在接收到NOTIFY事件队列出口。

1

虽然Evan的answer是正确的,但我认为这个问题可以从一个例子中受益。

这是我在这个问题的例子表使用的规则定义:

CREATE OR REPLACE RULE update_update_table 
AS ON UPDATE TO second_table 
DO ALSO (
    INSERT INTO table_updates (
    main_id, field 
) 
    SELECT DISTINCT OLD.main_id, 'cold'::field 
    WHERE NOT EXISTS (
    SELECT TRUE 
    FROM table_updates 
    WHERE main_id = OLD.main_id 
     AND field = 'cold' 
); 
    UPDATE table_updates 
    SET updated_on = NOW() 
    WHERE main_id = OLD.main_id 
    AND field = 'cold' 
)