我正在学习在PostgreSQL中使用触发器但遇到此代码的问题:
CREATE OR REPLACE FUNCTION checkAdressen() RETURNS TRIGGER AS $$
DECLARE
adrCnt int = 0;
BEGIN
SELECT INTO adrCnt count(*) FROM Adresse
WHERE gehoert_zu = NEW.kundenId;
IF adrCnt < 1 OR adrCnt > 3 THEN
RAISE EXCEPTION 'Customer must have 1 to 3 addresses.';
ELSE
RAISE EXCEPTION 'No exception';
END IF;
END;
$$ LANGUAGE plpgsql;
在新创建所有表后,我使用此过程创建了一个触发器,因此它们都是空的。但是,上面代码中的count(*)
函数返回1。
当我在PL / pgSQL之外运行SELECT count(*) FROM adresse;
时,我得到0。
我尝试使用FOUND
变量,但它始终是真的。
更奇怪的是,当我在表中插入一些值然后再次删除它们以使它们再次为空时,代码按预期工作,count(*)
返回0。
此外,如果我遗漏WHERE gehoert_zu = NEW.kundenId
,count(*)
会返回0,这意味着我使用WHERE
子句获得的结果比不使用CREATE TABLE kunde (
kundenId int PRIMARY KEY
);
CREATE TABLE adresse (
id int PRIMARY KEY,
gehoert_zu int REFERENCES kunde
);
CREATE CONSTRAINT TRIGGER adressenKonsistenzTrigger AFTER INSERT ON Kunde
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE checkAdressen();
INSERT INTO kunde VALUES (1);
INSERT INTO adresse VALUES (1,1);
更多。
- 编辑:
以下是我如何使用该程序的示例:
DEFERRABLE INITIALLY DEFERRED
看起来我的INSERT
部分错了。我假设触发器将在第一个BEGIN;
语句之后执行,但它会在第二个语句之后执行,尽管插入不在COMMIT;
- adresse
- Block中。
根据PostgreSQL Documentation插入,如果不在这样的块内,每次都会自动提交,因此当提交第一个INSERT
语句时,DEFERRABLE INITIALLY DEFERRED
中不应该有一个条目。
任何人都可以指出我的错误吗?
- 编辑:
触发器和BEGIN
似乎正常工作。
我的错误是假设因为我没有使用COMMIT
- BEGIN
- 阻止每个插入都将在自己的事务中执行,并且每次都会执行触发器。
然而,即使没有COMMIT
- BEGIN
,所有插入都会捆绑到一个事务中,之后会执行触发器。
鉴于此行为,使用COMMIT
- {{1}}?
答案 0 :(得分:1)
由于鸡肉和鸡蛋问题,您需要一个交易加上“可延迟初始延期”。
从两个空表开始:
这就是为什么你需要将两个插入捆绑到一个操作中的原因:事务。您需要BEGIN + COMMIT,并且DEFERRABLE允许临时禁止数据库状态存在:它会导致在提交时评估检查。
答案 1 :(得分:0)
这看起来有点傻,但答案是您需要停止推迟触发并运行插入BEFORE
。如果在插入后运行它,当然表中有数据。
据我所知,这是按预期工作的。
还有一点需要注意,你可能并不是说:
RAISE EXCEPTION 'No Exception';
你可能想要
RAISE INFO 'No Exception';
然后,您可以更改设置并在事务中运行查询,以测试触发器是否符合您的要求。实际上,每次插入都会失败,如果不编辑程序,就无法将其移植到生产环境中。