说我有下表:
create table A
(
identifier integer not null primary key,
title text not null,
... -- other fields
);
在A上执行UPDATE时,我一定不想只更新目标行,但我也想将更新应用到A中的另一行。我尝试编写'重写规则'或'触发前',但我总是以无限循环结束:
create function A(in A, in A) returns void as
$$
declare
i integer;
begin
-- do some logic which finds other row (hardcoded in this example)
i = 2;
-- update old row
update A set title = $2.title where identifier = $1.identifier;
-- apply updates to other row
update A set ... where identifier = i;
end;
$$ language plpgsql;
create rule A as on update to A do instead select A(old, new);
我测试的数据:
insert into A (identifier, title) values (1, 'old title 1');
insert into A (identifier, title) values (2, 'old title 2');
update A set title = 'new title 1' where identifier = 1;
使用“触发前”而不是“重写规则”时也会出现同样的问题。
如果需要,有没有办法绕过规则/触发器?我无法在第一行之后更改表A禁用规则A ,并且在返回之前 alter table A启用规则A ,因为表A正在使用,由我们自己。
的更新 的
我设法通过创建一个虚拟继承表来完成此操作,在该表上完成“内部更新”,而不是直接在表上。这会绕过触发器/规则。
drop table if exists A cascade;
create table A
(
identifier serial not null primary key,
title text not null
);
create table A_
(
) inherits (A);
create or replace function A() returns trigger as
$$
declare
i integer;
begin
-- create duplicate row
insert into A (title) values (new.title) returning identifier into i;
-- update new row
update A_ set title = new.title where identifier = i;
-- do not propagate update
return null;
end
$$ language plpgsql;
create trigger A before update on A for each row execute procedure A();
insert into A (title) values ('old title 1');
insert into A (title) values ('old title 2');
update A set title = 'new title 1' where identifier = 1;
select * from A;
答案 0 :(得分:3)
为了避免触发器中的无限循环,您需要添加一个额外的where子句,以避免多次重新影响一行:
update foo
set bar = 'baz'
where bar <> 'baz'
为了避免规则中的递归,不能做同样的事情,因为新的查询在原始的查询(和新的查询)被解析时被抛入,而不考虑单个查询的where子句。
答案 1 :(得分:3)
您可以使用功能pg_trigger_depth
来区分用户启动的UPDATE
和触发启动的UPDATE
。您甚至可以将其放入触发器声明的WHEN
子句中。以下是details from another question。