假设我有以下表格:
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表中导入列的总和。
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表中的限制。
我该如何解决?
谢谢!
答案 0 :(得分:2)
执行insert语句后执行AFTER 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触发器时,外部命令所做的所有数据更改都已完成,并且对调用的触发器函数可见。
您可以使用foo
中bar
的值之和来更新bar_insert()
:
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
包含其他一些数据,请从import
移除foo
并创建视图:
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;
您不需要任何触发器,所有触发器都会自动完成。