繁体   English   中英

由另一个触发器内的更新语句引起的触发器

[英]Trigger caused by an update statement inside another trigger

假设我有下表:

CREATE TABLE foo (
  id_foo int NOT NULL,
  import int NOT NULL,
  CONSTRAINT foo_pk PRIMARY KEY(id_foo)
);

CREATE TABLE bar (
  id_bar int NOT NULL,
  id_foo int NOT NULL,
  import int NOT NULL,
  CONSTRAINT bar_pk PRIMARY KEY(id_bar)
);

ALTER TABLE bar ADD CONSTRAINT fk_bar FOREIGN KEY(id_foo) REFERENCES foo(id_foo);

因此,foo表的import列必须等于bar表中的import列的总和。

CREATE OR REPLACE FUNCTION foo_restriction() RETURNS TRIGGER AS
$$
  BEGIN
    IF (NEW.import != (SELECT COALESCE(SUM(import),0) FROM bar WHERE id_foo = NEW.id_foo)) THEN
      RAISE EXCEPTION 'import column in foo must be equal in bar table.';
    END IF;

    RETURN NEW;
  END;
$$
LANGUAGE plpgsql;

但是我想自动将bar中的新导入值求和到foo引用。

CREATE OR REPLACE FUNCTION bar_insert() RETURNS TRIGGER AS
$$
  BEGIN
    UPDATE foo SET import = import + NEW.import WHERE id_foo = NEW.id_foo;
    RETURN NEW;
  END;
$$
LANGUAGE plpgsql;


CREATE TRIGGER TR_fooRestriction AFTER INSERT OR UPDATE ON foo FOR EACH ROW EXECUTE PROCEDURE foo_restriction();
CREATE TRIGGER TR_barInsert AFTER INSERT ON bar FOR EACH ROW EXECUTE PROCEDURE bar_insert();

然后,以下语句不起作用:

INSERT INTO foo(id_foo, import) VALUES(1,25); --FAIL. Works ok.

以下指令为foo插入一个正确的元组,import = 0。

INSERT INTO foo(id_foo, import) VALUES(2,0); --OK.

但是,当我尝试在bat表中添加新值时,数据库显示“在foo中的import列必须在bar表中相等”。

INSERT INTO bar(id_bar, id_foo, import) VALUES
(1,2,100),(2,2,160),(3,2,40);

这是怎么回事?两个触发器都在每个新行之后执行,因此foo表中的限制不应在最后一条语句中激活。

我该如何解决?

谢谢!

AFTER INSERT触发器是在执行insert语句之后而不是在插入每一行之后执行的。 因此,触发器在插入单行的语句中应该能很好地工作,但在多行插入中则不能。 要测试此行为,请在psql中运行以下脚本:

drop table if exists test;
create table test (id int);

create or replace function test_trigger()
returns trigger language plpgsql as $$
begin
    raise notice '%', (select count(*) from test);
    return null;
end $$;

create trigger test_trigger 
after insert on test 
for each row execute procedure test_trigger();

insert into test values (1), (2), (3);

DROP TABLE
CREATE TABLE
CREATE FUNCTION
CREATE TRIGGER
NOTICE:  3
NOTICE:  3
NOTICE:  3
INSERT 0 3

对于文档

当触发行级AFTER触发器时,外部命令进行的所有数据更改都已完成,并且对调用的触发器函数可见。


您可以使用bar_insert() bar的值的总和来更新foo

    update foo 
    set import = (
        select sum(import) 
        from bar where id_foo = new.id_foo)
    where id_foo = new.id_foo;
    return null;

但是,最好的解决方案是视图。 如果foo仅聚合import ,则删除表并创建视图:

create or replace view foo_view as 
    select id_foo, sum(import) as import
    from bar
    group by id_foo;

如果foo包含其他数据,请从foo删除import并创建视图:

create or replace view foo_view as 
    select foo.*, sum(bar.import) as import_total
    from bar
    join foo using(id_foo)
    group by foo.id_foo;

您不需要任何触发器,所有操作都是自动完成的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM