Скажите, у меня есть следующая таблица:
create table A
(
identifier integer not null primary key,
title text not null,
... -- other fields
);
При выполнении UPDATE для A я не хочу обновлять только целевую строку, но я также хочу применить обновления к другой строке в 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 после первой строки, и изменить таблицу 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;