postgresql - PostgreSQL 中的 PL/pgSQL 查询返回新的空表的结果

标签 postgresql plpgsql

我正在学习在 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.kundenIdcount(*) 将返回 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; - block 。

根据PostgreSQL Documentation如果不在这样的 block 内,每次都会自动提交插入,因此当提交第一个 INSERT 语句时,adresse 中不应有条目。

谁能指出我的错误?

--编辑:

触发器和 DEFERRABLE INITIALLY DEFERRED 似乎工作正常。 我的错误是假设因为我没有使用 BEGIN-COMMIT-Block,所以每次插入都将在自己的事务中执行,每次都会在之后执行触发器。

然而,即使没有 BEGIN-COMMIT,所有插入也会被捆绑到一个事务中,触发器会在之后执行。 鉴于这种行为,使用 BEGIN-COMMIT 有什么意义?

最佳答案

由于先有鸡还是先有蛋的问题,您需要一个交易加上“DEFERRABLE INITIALLY DEFERRED”。


从两个空表开始:

  • 您不能向人员表中插入一行,因为它至少需要一个地址。
  • 不能在 address 表中插入一行,因为 FK 约束需要 person 表上存在相应的行

这就是为什么您需要将两个插入捆绑到一个操作中:事务。您需要 BEGIN+ COMMIT,并且 DEFERRABLE 允许 transient 禁止的数据库状态存在:它导致在提交时评估检查。

关于postgresql - PostgreSQL 中的 PL/pgSQL 查询返回新的空表的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18516816/

相关文章:

postgresql:在动态命令中使用 NEW.* 执行

function - 从 plpgsql 函数返回多行

c - 使用 libpq 库将图像发送到 postgresql 数据库中的 bytea 列时出错

postgresql - 如何在 postgresql 中显示用户的 udt 定义?

sql - 优化 LATERAL join 中的慢聚合

postgresql - 触发 reshape 电话号码

sql - 在 Postgres 中使用动态查询 + 用户定义的数据类型

sql - 查询以获取给定表列的相关 View 定义和详细信息

sql - postgres根据条件执行存储过程

function - Postgres 创建时间戳转换函数