如何从存储过程(不是函数)返回值?

时间:2020-07-19 14:26:45

标签: postgresql stored-procedures parameter-passing plpgsql

我有一个存储过程,可以插入,更新或删除表行。当所有参数都用作输入时,它运行良好。但是,我需要返回最后插入的行的ID。为此,我尝试使用INOUT参数和RETURNING语句后的INSERT返回ID。

但是,我不确定如何将返回的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

1 个答案:

答案 0 :(得分:1)

概念证明

PROCEDURE 可以返回值,但是返回值非常有限(自Postgres 13起)。

The manual on CALL:

CALL执行一个过程。

如果该过程具有任何输出参数,则结果行将为 返回,其中包含这些参数的值。

The manual on CREATE PROCEDURE:

argmode

自变量的模式:ININOUTVARIADIC。如果省略,则默认值为IN。 (过程目前不支持OUT自变量。请改为使用INOUT。)

因此,您对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 <>提琴here

以此作为概念证明。但是,我认为问题没有任何内容可以保证首先使用PROCEDURE

您可能想要一个FUNCTION

FUNCTION提供了更多返回值的选项,不需要与CALL分开运行,并且可以集成到更大的查询中。首先,这就是您想要的,而您只是被广泛使用的错误的“存储过程”误导了。参见:

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

经验法则:如果不需要从内部管理事务,则可能要使用函数而不是过程。以后,可以将Postgres过程扩展为能够并返回多个结果集(根据SQL标准),但尚未返回(第13页)。

请参阅: