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

7fyelxc5  于 2023-05-28  发布在  PostgreSQL
关注(0)|答案(2)|浏览(474)

我有一个插入、更新或删除表行的存储过程。当所有参数都用作输入时,它工作正常。但是,我需要返回最后插入行的ID。为此,我尝试在INSERT语句后使用INOUT参数和RETURNING来返回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
zhte4eai

zhte4eai1#

概念证明

一个PROCEDURE * 可以 * 返回值,但以非常有限的方式(从Postgres 13开始)。
The manual on CALL :
CALL执行一个过程。
如果过程有任何输出参数,则将返回一个结果行,其中包含这些参数的值。
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$;

把这个当作概念的证明。但是我在问题中没有看到任何东西可以保证首先使用PROCEDURE

你可能需要一个FUNCTION

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

  • 如何从PostgreSQL存储过程中获取结果集?

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

rule of thumb:如果您不需要从内部管理事务,您可能希望使用函数而不是过程。稍后,Postgres过程可能会扩展到能够返回多个结果集(根据SQL标准),但还没有(第13页)。

参见:

dohp0rv5

dohp0rv52#

我在我的过程中使用了inout参数,然后选择假设计数到那个inout变量中,我可以从过程中返回多个输出。

相关问题