То, что вы хотите сделать, не так уж сложно, я вам покажу. Но сначала: это очень очень плохая идея. На самом деле достаточно плохо, что некоторые базы данных, в частности Oracle, выдают исключение, если пытаются. К сожалению, Postgres позволяет это. По сути, вы создаете рекурсивное обновление при обновлении таблицы, которая инициировала триггер. Это обновление, в свою очередь, запускает триггер. Без логики, чтобы остановить эту рекурсию, вы можете обновить каждую строку в таблице. Я предполагаю, что это выдержка для гораздо большего требования, или, возможно, вы просто хотите знать, как создать триггер. Итак, мы начинаем:
-- setup
drop table if exists tokens;
create table tokens( id integer, amount numeric(6,2));
-- create initial test data
insert into tokens(id, amount)
values (1,100), (2,150.69), (3,95.50), (4,75), (5,16.40);
Теперь сердечный триггер Postgres: функция запуска и триггер. Обратите внимание, что функция должна быть определена до триггера, который ее вызывает.
-- create a trigger function: That is a function returning trigger.
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin
if new.id = 1
then
update tokens
set amount = new.amount
where id = 2;
end if;
return new;
end ;
$$;
-- create the trigger
create trigger tokens_bur
before update of amount
on tokens
for each row execute procedure tokens_bur_func();
--- test
select *
from tokens
order by id;
-- do an initial update
update tokens
set amount = 200
where id = 1;
-- Query returned successfully: one row affected, 31 msec execution time.
-- 1 row? Yes: DML count does not see change made from within trigger.
-- but
select *
from tokens
order by id;
Жесткие идентификаторы кодирования в триггере, однако, не очень функциональны, поскольку «update ... where id in (1,2)» будет намного проще и безопаснее, поскольку не требует рекурсииостанови логику. Итак, чуть более общая триггерная функция:
-- More general but still vastly limited:
-- trigger that mirrors subsequent row whenever an odd id is updated.
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin
if mod(new.id, 2)=1
then
update tokens
set amount = new.amount
where id = new.id+1;
end if;
return new;
end ;
$$;
-- test
update tokens
set amount = 900
where id = 3;
update tokens
set amount = 18.95
where id in (2,5);
select *
from tokens
order by id;
Независимо от того, как вы поступите, вам потребовалось предварительное знание специфики обновления. Например, вы сказали, что «это может быть id 2, для этого я могу установить mirror from id 3», поэтому вам потребуется каким-либо образом изменить базу данных, либо изменив функцию триггера, либо триггер для передачи параметров. (Триггеры могут передавать параметры, но они являются статическими, предоставленными во время создания триггера). Наконец, убедитесь, что вы поняли логику остановки рекурсии. Потому что если нет:
-- The Danger: What happens WITHOUT the 'stopper condition'
-- Using an almost direct conversion of your UDT
-- using new_id as
create or replace function tokens_bur_func()
returns trigger
language plpgsql
as $$
begin
update tokens
set amount = new.amount
where id = new.id+1;
return new;
end ;
$$;
-- test
update tokens
set amount = 137.92
where id = 1;
-- Query returned successfully: one row affected, 31 msec execution time.
-- but
select *
from tokens
order by id;