我正在学习在 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。当我SELECT count(*) FROM adresse;
在 PL/pgSQL 之外运行时,我得到 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;
- 块内。
根据PostgreSQL 文档,如果不在这样的块内,每次都会自动提交插入,因此在提交adresse
第一条INSERT
语句时不应该有条目。
谁能指出我的错误?
- 编辑:
触发器DEFERRABLE INITIALLY DEFERRED
似乎工作正常。我的错误是假设由于我没有使用BEGIN
--BlockCOMMIT
每个插入都将在自己的事务中执行,并且每次都在之后执行触发器。
然而,即使没有BEGIN
-COMMIT
所有插入都会被捆绑到一个事务中,然后触发器会被执行。鉴于这种行为,使用BEGIN
-有什么意义COMMIT
?