Postgres存储过程中的意外OUT值

时间:2019-01-06 18:06:50

标签: sql database postgresql stored-procedures plpgsql

使用Postgres10。

我遇到一个问题,我正在调用存储过程并期望OUT参数具有特定值,但我没有得到。我正在使用下面的调用代码调用Items存储过程。

问题 我希望我第一次调用Item存储过程来获得rtn值为1的插入,但得到4的插入。这意味着IF EXISTS正在表中查找具有相同名称的行,但是我的表为空

我期望在INSERT语句之后重新评估IF EXISTS语句并进入rtn设置为4的块时,会发生一些奇怪的事情,这与plpgsql有关吗?当我使用Raise命令在某些点测试值时,就好像存储过程的顺序并不总是从上到下。

SCHEMA / TABLE

compile 'com.android.support:appcompat-v7:26.0.2'

存储过程

CREATE TABLE aips.Item (
 ItemPk SERIAL PRIMARY KEY,
 Name VARCHAR(100) NOT NULL,
 CONSTRAINT UNI_Item_Name UNIQUE(Name)
);

致电

CREATE OR REPLACE FUNCTION aips.Item(
    INOUT p_ItemPk INT,
    INOUT p_Name VARCHAR(100),
    OUT rtn INT
) AS
$$
DECLARE rowcnt INT;
BEGIN
  -- Insert or Find Path
  IF p_ItemPk IS NULL THEN

    -- Check for Find
    IF EXISTS (SELECT * FROM aips.Item where Name = p_Name) THEN
        SELECT ItemPk, Name
        INTO p_ItemPk, p_Name
        FROM aips.Item
        WHERE Name = p_Name;

        rtn := 4;
        RETURN;
    END IF;

    -- Perform insert
    INSERT INTO aips.Item (Name)
    VALUES (p_Name)
    RETURNING ItemPk INTO p_ItemPk;
    GET DIAGNOSTICS rowcnt = ROW_COUNT;

    IF rowcnt = 1 THEN
      rtn := 1;
    ELSE
      rtn := 0;
      RAISE EXCEPTION 'Expecting to insert a single row and rows returned --> %', rowcnt;
    END IF;

  ELSE -- Update or No Operation Path

    -- Check for no changes
    IF EXISTS (SELECT ItemPk 
               FROM aips.Item 
               WHERE ItemPk = p_ItemPk
               AND Name = p_Name) THEN
        rtn := 5;
        RETURN;
    END IF;

    -- Perform Update
    UPDATE aips.Item 
    SET Name = p_Name
    WHERE ItemPk = p_ItemPk;
    GET DIAGNOSTICS rowcnt = ROW_COUNT;

    IF rowcnt = 1 THEN
      rtn := 2;
    ELSE
      rtn := 0;
      RAISE EXCEPTION 'Expecting to update a single row and rows returned --> %', rowcnt;
    END IF;
  END IF;

  RETURN;
END;
$$ LANGUAGE plpgsql;

1 个答案:

答案 0 :(得分:1)

问题在于调用函数的方式:

select (aips.Item(NULL, 'Test 1')).*; -- WRONG!

因为它执行了3次,每个输出列一次。该函数应在FROM子句中调用:

select * from aips.Item(NULL, 'Test 1');