PostgreSQL触发器阻止另一个工作

时间:2017-06-07 21:07:45

标签: postgresql triggers plpgsql database-trigger

假设我们有:

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列中的更新。

有什么想法吗?谢谢!

1 个答案:

答案 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以防止ctrg2_change的更改计算c值。