我有两张表格,其中包含与日常业务相关的数据:
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_updates
次查询之前更新UPDATE
,满足了跟踪四个列更新中的三个的需求。
我可以轻松地将相同类型的触发器添加到second_table
,但是由于main_id
不唯一,因此可以对单个main_id
值执行多次函数,这是不可取的
如何创建一个函数,当更新second_table
中的多行时,每main_id
只执行一次?
答案 0 :(得分:2)
如何创建一个函数,当更新second_table中的多行时,每个main_id只执行一次?
如果您的插入符号是由main_id插入的,即INSERT INTO tbl (main_id...) VALUES (main_id ...),(main_id ...),(main_id ...)
,您可以使用rule system触发一次INSERT
或UPDATE
对于两者都可以实现的事情,最好取决于数据库的用法。 为每个受影响的行触发一次触发器。规则会修改查询或生成其他查询。因此,如果在一个语句中影响了许多行,则发出一个额外命令的规则可能比为每一行调用的触发器更快,并且必须重新生成确定要做多次。但是,触发器方法在概念上远比规则方法简单,并且新手更容易正确。
羞涩的是,您可能还想查看正常的LISTEN
和NOTIFY
。这使您能够使用异步操作。如果那是您的事情,并且您决定通过tcn
继续考虑触发器更改通知模块。
我的建议是尽可能在应用程序(数据库之外)中执行此操作。请记住,PostgreSQL temp
表是会话的本地表。所以你可以让每个加载器会话做这样的事情,
BEGIN
CREATE TEMP TABLE UNLOGGED etl_inventory;
COPY foo FROM stdin;
-- Are they different, if so `NOTIFY`
-- UPSERT
COMMIT;
然后有一个守护进程在收到NOTIFY
事件时将导出添加到导出队列。
答案 1 :(得分: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'
)