如何 return 来自存储过程(不是函数)的值?

How to return a value from a stored procedure (not function)?

我有一个存储过程可以插入、更新或删除表行。当所有参数都用作输入时,它工作正常。但是,我需要 return 最后插入行的 ID。为此,我尝试在 INSERT 语句之后使用 INOUT 参数和 RETURNING 来 return ID。

但是,我不确定如何将 returned ID 绑定到 INOUT 参数。以下是存储过程的代码:

CREATE OR REPLACE PROCEDURE public.spproductinsertupdatedelete(
_ser integer,
_subcategid integer,
_inrprice numeric,
_usdprice numeric,
_colour integer,
_size integer,
_qty integer,
_prodid integer DEFAULT NULL::integer,
inout _pid integer default null
 )
LANGUAGE 'plpgsql'
AS $BODY$

BEGIN
  if _ser=1 then --- Insert
    INSERT INTO product (prod_subcateg_id,prod_inr_price,prod_usd_price,prod_colour,prod_size,prod_qty)
    VALUES (_subcategID, _inrprice, _usdprice, _colour, _size, _qty)
    RETURNING prod_id;

ELSEIF _ser=2 THEN
    
    UPDATE PRODUCT SET
    prod_subcateg_id = _subcategid,
    prod_inr_price = _inrprice,
    prod_usd_price = _usdprice,
    prod_size = _size,
    prod_colour = _colour,
    prod_qty=_qty
    where prod_id = _prodID;

ELSEIF _ser=3 THEN ---- Delete
    UPDATE PRODUCT SET prod_datetill = now()
    WHERE prod_id = _prodID;
    
end if;

END
$BODY$;

在执行上述存储过程时,我收到此错误:

ERROR:  query has no destination for result data

概念验证

A PROCEDURE 可以 return 值,但以非常有限的方式(从 Postgres 13 开始)。

The manual on CALL:

CALL executes a procedure.

If the procedure has any output parameters, then a result row will be returned, containing the values of those parameters.

The manual on CREATE PROCEDURE:

argmode

The mode of an argument: IN, INOUT, or VARIADIC. If omitted, the default is IN. (OUT arguments are currently not supported for procedures. Use INOUT instead.)

所以你对INOUT模式的使用是正确的。但是缺少函数体中的赋值。还有一些其他的事情是错误的/次优的。我建议:

CREATE OR REPLACE PROCEDURE public.spproductinsertupdatedelete(
  _ser        int
, _subcategid int
, _inrprice   numeric
, _usdprice   numeric
, _colour     int
, _size       int
, _qty        int
, INOUT _prod_id int DEFAULT NULL
)
  LANGUAGE plpgsql AS
$proc$
BEGIN
   CASE _ser    -- simpler than IF
   WHEN 1 THEN  -- INSERT
      INSERT INTO product
             (prod_subcateg_id, prod_inr_price, prod_usd_price, prod_colour, prod_size, prod_qty)
      VALUES (_subcategid     , _inrprice     , _usdprice     , _colour    , _size    , _qty    )
      RETURNING prod_id
      INTO _prod_id;   -- !!!

   WHEN 2 THEN  -- UPDATE
      UPDATE product
      SET   (prod_subcateg_id, prod_inr_price, prod_usd_price, prod_size, prod_colour, prod_qty)
          = (_subcategid     , _inrprice     , _usdprice     , _size    , _colour    , _qty)
      WHERE  prod_id = _prod_id;

   WHEN 3 THEN  -- soft-DELETE
      UPDATE product
      SET    prod_datetill = now()
      WHERE  prod_id = _prod_id;

   ELSE
      RAISE EXCEPTION 'Unexpected _ser value: %', _ser;
   END CASE;
END
$proc$;

db<>fiddle here

以此作为概念证明。但是我在问题中看不到任何东西首先需要使用 PROCEDURE

你可能想要 FUNCTION

A FUNCTION 为 return 值提供了更多选项,不需要 运行 与 CALL 分开,并且可以集成到更大的查询中。很有可能,这正是您最初想要的,而您只是被广泛使用的误称“存储过程”误导了。参见:

此外,在当前的形式中,如果要更新或软删除一行,则必须提供许多噪声参数。普通 SQL 命令可能会完成这项工作。或者单独的功能...

经验法则:如果您不需要从内部管理事务,您可能希望使用函数而不是过程。稍后,Postgres 过程可能会扩展为能够 return 多个结果集(根据 SQL 标准),但目前还不能(第 13 页)。

参见: