Postgresql 忽略 if 条件

Postgresql ignoring if condition

我正在尝试了解 plpgsql 中的事务,我想要一些解释。

我有这个代码:

CREATE OR REPLACE PROCEDURE MaJ(mode IN INT)
AS
$$
DECLARE
r RECORD;
DECLARE
r RECORD;
BEGIN
    FOR r IN SELECT id, fname, lname, bday FROM usr
        LOOP
            IF r.ID % 2 = 0 THEN
                UPDATE usr SET lname = 'KONAN';
                RAISE NOTICE E'fname : %\n', r.lname;
            END IF;
        END LOOP;
    IF mode = 0 THEN
        COMMIT;
    ELSE IF mode = 1 THEN
        ROLLBACK;
    END IF;
END;

我正在使用 CALL MaJ(VAL);

从另一个过程调用此过程

更新: 也许这段代码更好地描述了问题: 这是我正在尝试做的事情:

CREATE OR REPLACE PROCEDURE CRDM(Crtrn INOUT INT)
AS
$CRDM$
DECLARE
R RECORD;
BEGIN
    
        FOR R IN SELECT * FROM usr
            LOOP
                IF R.ID % 2 = 0 THEN
                    UPDATE USR SET lname = 'MAGNI' WHERE USR.ID = R.ID;
                END IF;
            END LOOP;
        IF Crtrn = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
END;
$CRDM$ LANGUAGE plpgsql;

CREATE OR REPLACE PROCEDURE AMI() 
AS
$AMI$
DECLARE
rtrn INT:=0;
BEGIN
    BEGIN
        CALL CRDM(rtrn);
    END;
END;
$AMI$ LANGUAGE plpgsql;

DO
$$
BEGIN
    CALL AMI();
END;
$$ LANGUAGE plpgsql;

欢迎就我遗漏的内容以及如何更好地思考交易提供任何帮助。

您的“提交;”和“回滚;”读完这篇文章后我觉得逻辑没问题:https://www.postgresql.org/docs/current/plpgsql-transactions.html

您可能需要“开始;”在您“调用”您的程序之前的交易:我不确定。

您的第二个问题很简单:您的 UPDATE 语句没有 WHERE 子句。确保通过匹配 ID 值仅更新当前循环记录。

只有在新版本中才能使用 ROLLBACKCOMMIT。如果支持这些命令,请检查您使用的版本。

很长一段时间 Postgres 存储过程没有这些命令也没有问题。在 PL/pgSQL 中使用 COMMITROLLBACK 并不太原生——主要是为了更容易从 Oracle 迁移而实现的,但是因为 Oracle 和 Postgres 的事务模型非常不同,所以有很多限制。

Oracle 在登录后启动隐式事务并等待显式 commitrollback。在这些命令之后,Oracle 立即开始新事务。

在 Postgres 中,每条语句都像在 Oracle 中一样在事务下执行。但如果交易是由用户发起的,则用户负责 commitrollback。如果用户没有启动事务,则 Postgres 启动事务,并且 Postgres 在操作引发异常时隐式运行 rollback,否则运行 commit。异常后只允许rollback

通常在 Postgres 中没有必要使用 commitrollback。只需引发异常,上层就会完成所有必要的工作。

你的代码不好,请尝试阅读文档和一些关于编程风格的注释。不要使用 Camel 表示法 - 不区分大小写的语言。

CREATE TABLE foo_tab(id int);
CREATE TABLE boo_tab(id int, b text);

INSERT INTO foo_tab VALUES(1);
INSERT INTO foo_tab VALUES(2);

CREATE OR REPLACE PROCEDURE foo(a bool, b text)
AS $$
DECLARE r record;
BEGIN
  FOR r IN SELECT * FROM foo_tab
  LOOP
    INSERT INTO boo_tab VALUES(r.id, b);
  END LOOP;
  IF a THEN
    COMMIT;
  ELSE
    ROLLBACK;
  END IF;
END
$$ LANGUAGE plpgsql;

CREATE OR REPLACE PROCEDURE foo2(a bool, b text)
AS $$
BEGIN
  CALL foo(a, b);
END;
$$ LANGUAGE plpgsql;

DO $$
BEGIN
  CALL foo2(true, 'Ahoj');
  CALL foo2(false, 'Nazdar');
END;
$$; -- LANGUAGE plpgsql is implicit here

postgres=# SELECT * FROM boo_tab;
┌────┬──────┐
│ id │  b   │
╞════╪══════╡
│  1 │ Ahoj │
│  2 │ Ahoj │
└────┴──────┘
(2 rows)

在 Postgres 13 上测试