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

PostgreSQL中的PL/pgSQL查询返回新的空表的结果,postgresql,plpgsql,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 THE

我正在学习在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;
看起来我把
可延迟的初始延迟部分弄错了。我假设触发器将在第一条
INSERT
语句之后执行,但它发生在第二条语句之后,尽管插入不在
BEGIN语句中-
提交-块

根据这一点,如果不是在这样一个块内,则每次都会自动提交插入,因此在提交第一个
INSERT
语句时,
adrese
中不应该有条目

有人能指出我的错误吗

--编辑:

触发器和
可延迟最初延迟的
似乎工作正常。 我的错误是假设由于我没有使用
BEGIN
-
COMMIT
-块,每次插入都会在自己的事务中执行,之后每次都会执行触发器

但是,即使没有
BEGIN
-
COMMIT
也会将所有插入绑定到一个事务中,然后执行触发器。
考虑到这种行为,使用
BEGIN
-
COMMIT
有什么意义?

这似乎有点愚蠢,但答案是您需要停止延迟触发器,并在插入之前运行它。如果在插入之后运行它,表中当然有数据

据我所知,这是工作的预期

还有一点,你可能不是说:

RAISE EXCEPTION 'No Exception';
你可能想要

RAISE INFO 'No Exception';

然后,您可以更改设置并在事务中运行查询,以测试触发器是否执行您希望它执行的操作。实际上,每次插入都会失败,如果不编辑您的过程,您就无法将其投入生产。

这似乎有点愚蠢,但答案是您需要停止延迟触发器,并在插入之前运行它。如果在插入之后运行它,表中当然有数据

据我所知,这是工作的预期

还有一点,你可能不是说:

RAISE EXCEPTION 'No Exception';
你可能想要

RAISE INFO 'No Exception';

然后,您可以更改设置并在事务中运行查询,以测试触发器是否执行您希望它执行的操作。事实上,每次插入都会失败,如果不编辑您的过程,您将无法将其转入生产。

您需要一个事务加上“可延迟的初始延迟”,因为鸡和蛋的问题


从两个空表开始:

  • 不能在person表中插入一行,因为它至少需要一个地址
  • 无法在地址表中插入单行,因为FK约束需要person表上的对应行才能存在


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

由于鸡和蛋的问题,您需要一个事务加上“DEFERRABLE INITIALLY DEFERRED”


从两个空表开始:

  • 不能在person表中插入一行,因为它至少需要一个地址
  • 无法在地址表中插入单行,因为FK约束需要person表上的对应行才能存在


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

如果您可以将一个简单的示例与空表和触发器定义结合起来,这将非常有用。我猜问题在别处。哦,如果不使用camelCase标识符,您可能会发现生活更轻松。坚持使用小写字母,加上下划线,从长远来看,这样会减少麻烦。看起来你是对的。我只是重新创建了相关的部分,它的工作。这个问题似乎是由其他表定义引起的。“插入是自动提交的”:这取决于您的SQL客户机(可能还有它的配置方式)。如果您的SQL工具禁用自动提交,则只有在运行
commit
时才会提交插入;我使用的是pgAdmin III。插入的提交没有
提交语句,因此必须启用自动提交。如果您可以将一个简单的示例与空表和触发器定义结合起来,这将非常有用。我猜问题在别处。哦,如果不使用camelCase标识符,您可能会发现生活更轻松。坚持使用小写字母,加上下划线,从长远来看,这样会减少麻烦。看起来你是对的。我只是重新创建了相关的部分,它的工作。这个问题似乎是由其他表定义引起的。“插入是自动提交的”:这取决于您的SQL客户机(可能还有它的配置方式)。如果您的SQL工具禁用自动提交,则只有在运行
commit
时才会提交插入;我使用的是pgAdmin III。插入的提交没有
提交语句,因此必须启用自动提交。我的假设是,由于我没有使用
BEGIN
-
COMMIT
-块,因此每次插入都会自行提交,每次插入后都会执行触发器。但即使并没有这样的块,所有插入都被捆绑到一个事务中。因此,我想知道
BEGIN
-
COMMIT
有什么用。@TillS,不是真的。PostgreSQL中的所有内容都在显式或隐式事务中。如果只有一条语句,则该语句及其触发的触发器位于同一事务中。因此,任何异常都将导致执行插入的事务中止。现在有一件事不清楚