假设我们有:
create table T
(
id bigserial primary key
, a int
, b int
, c int
);
我希望c
始终等于a+b
,我希望阻止c
的手动更改。所以我创建了两个触发器:
-- Prevents manual changes of c:
create or replace function no_changes() returns trigger as $$
begin
if old.c is distinct from new.c then
raise exception 'Can''t change c manually.';
end if;
return new;
end;
$$ language plpgsql;
create trigger no_changes
before update of c -- 'before' so prevents changes in 'c'
on T
for each row
execute procedure no_changes();
-- Do c = a + b:
create or replace function change() returns trigger as $$
begin
update T
set c = a + b
where id = new.id;
return new;
end;
$$ language plpgsql;
create trigger change
after insert or update of a, b -- 'after' so I'm sure the row is inserted/updated
on T
for each row
execute procedure change();
如果我这样做:
update T set c = 247;
我看到错误消息“无法手动更改c”,并且列不会更改。大。
但是,如果我这样做:
insert into T (a, b) values (4, 3);
或者:
update T set a = 3 where id = 2 -- suppose id = 2 exists
然后我收到与以前相同的错误消息。显然,update
触发器中的change
命令会触发no_changes
触发器,阻止c
列中的更新。
有什么想法吗?谢谢!
答案 0 :(得分:4)
整个逻辑可以放在单一功能中:
create or replace function change() returns trigger as $$
begin
if old.c is distinct from new.c then
raise exception 'Can''t change c manually.';
end if;
new.c := new.a + new.b;
return new;
end;
$$ language plpgsql;
create trigger change
before insert or update on T
for each row
execute procedure change();
但是如果你更喜欢分裂逻辑,那么
1)在before
事件
上创建两个触发器
2)"If multiple triggers of the same kind are defined for the same event, they will be fired in alphabetical order by name."因此命名触发器以获得所需的顺序,例如trg1_check
以防止c
和trg2_change
的更改计算c
值。