![](/img/trans.png)
[英]PostgreSQL PL/pgSQL : query stored within a table (opening hours)
[英]PL/pgSQL query in PostgreSQL returns result for new, empty table
我正在学习在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
语句之后执行,但它会在第二个INSERT
语句之后执行,尽管插入内容不在BEGIN;
- COMMIT;
-块
根据PostgreSQL文档刀片自动每次COMMITED如果没有这样一个块内,因此不应该有一个条目中的adresse
当第一INSERT
语句将提交。
谁能指出我的错误?
- 编辑:
触发器和DEFERRABLE INITIALLY DEFERRED
似乎工作正常。 我的错误是假设由于我不使用BEGIN
- COMMIT
-Block,所以每个插入操作都将在自己的事务中执行,而触发器每次之后都将执行。
但是,即使没有BEGIN
- COMMIT
所有插入也都捆绑到一个事务中,然后执行触发器。 鉴于这种行为,使用BEGIN
- COMMIT
什么意义?
由于鸡肉和鸡蛋的问题,您需要进行一笔交易,并加上“可延期的初始延期”。
从两个空表开始:
这就是为什么您需要将两个插入内容捆绑到一个操作中:事务。 您需要BEGIN + COMMIT,并且DEFERRABLE允许存在暂时禁止的数据库状态 :这将导致在提交时评估检查。
这似乎有点愚蠢,但是答案是您需要停止延迟触发器,并在插入BEFORE
运行它。 如果您在插入后运行它,那么表中当然会有数据。
据我所知,这按预期工作。
进一步说明,您可能不是要说的:
RAISE EXCEPTION 'No Exception';
你可能想要
RAISE INFO 'No Exception';
然后,您可以更改设置并在事务中运行查询以测试触发器是否按照您希望的方式进行。 实际上,每个插入都会失败,如果不编辑过程就无法将其移入生产环境。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.