带有IN子句参数的Oracle存储过程

ttisahbt  于 2022-10-04  发布在  Oracle
关注(0)|答案(8)|浏览(213)

如何创建一个Oracle存储过程,以接受用于馈送IN子句的可变数量的参数值?

这就是我正在努力实现的目标。我不知道如何在PLSQL中声明传递我想要更新的行的主键的变量列表。

FUNCTION EXECUTE_UPDATE
  ( <parameter_list>
   value IN int)
  RETURN  int IS
BEGIN 
    [...other statements...]
    update table1 set col1 = col1 - value where id in (<parameter_list>) 

    RETURN SQL%ROWCOUNT ;
END;

此外,我想从C#调用此过程,因此它必须与.NET功能兼容。

谢谢你,罗伯特

7xzttuei

7xzttuei1#

使用CSV可能是最简单的方法,假设您可以100%确定您的元素本身不会包含字符串。

执行此操作的另一种方法是创建自定义类型作为字符串表,这可能是更可靠的方法。假设您的字符串不超过100个字符,那么您可以:

CREATE TYPE string_table AS TABLE OF varchar2(100);

然后,可以将此类型的变量传递到存储过程中并直接引用它。在你的案例中,大概是这样的:

FUNCTION EXECUTE_UPDATE(
    identifierList string_table,
    value int)
RETURN int
IS
BEGIN

    [...other stuff...]

    update table1 set col1 = col1 - value 
    where id in (select column_value from table(identifierList));

    RETURN SQL%ROWCOUNT;

END

table()函数将您的自定义类型转换为具有单个列“COLUMN_VALUE”的表,然后您可以像对待任何其他表一样处理该表(连接也是如此,在本例中是子选择)。

这样做的好处是Oracle将为您创建一个构造函数,因此在调用您的存储过程时,您可以简单地编写:

execute_update(string_table('foo','bar','baz'), 32);

我假设您可以从C#以编程方式构建此命令。

顺便说一句,在我的公司,我们有许多这样的定制类型被定义为字符串、双精度、整型等列表的标准。我们还利用Oracle JPublisher能够直接从这些类型Map到相应的Java对象。我快速地环顾了一下周围,但我没有看到任何与C#直接对应的东西。我只是想提一下,以防Java开发人员遇到这个问题。

gz5pxeao

gz5pxeao2#

我认为没有直接的方法来创建具有可变数量的参数的过程。然而,如here所述,这个问题有一些,至少是部分解决方案。

1.如果有一些典型的调用类型,过程重载可能会有所帮助。
1.如果参数数量有上限(且其类型也已预先知道),则参数的默认值可能会有所帮助。
1.最好的选择可能是使用游标变量,它们是指向数据库游标的指针。

不幸的是,我没有.NET环境的经验。

des4xlb0

des4xlb03#

我找到了马克·A·威廉姆斯的以下文章,我认为这将是对这个帖子的有用补充。本文给出了一个使用关联数组将数组从C#传递到PL/SQL过程的很好的例子(myType类型是myable.row%type index by PLS_INTEGER的表):

Great article by Mark A. Williams

kmb7vmvb

kmb7vmvb4#

为什么不使用一个长参数列表并将值加载到表构造函数中呢?以下是此技巧的SQL/PSM

UPDATE Foobar
   SET x = 42
 WHERE Foobar.keycol
      IN (SELECT X.parm
            FROM (VALUES (in_p01), (in_p02), .., (in_p99)) X(parm)
           WHERE X.parm IS NOT NULL);
ibps3vxo

ibps3vxo5#

只需将变量拆分为逗号分隔的字符串:

declare
schema_n VARCHAR2 (30);
schema_size          number;
schemas       VARCHAR2 (30);
begin
schema_n := 'USER_PROD01,USER_PROD01' ;

select sum(bytes)/1024/1024 INTO schema_size FROM dba_segments where owner in (
with rws as (
  select ''||schema_n||'' str from dual
)
  select regexp_substr (
           str,
           '[^,]+',
           1,
           level
         ) value
  from   rws
  connect by level <= 
    length ( str ) - length ( replace ( str, ',' ) ) + 1

) ;
DBMS_OUTPUT.PUT_LINE ('PAY ATTENTION : PROD '||schemas||' user size is in total of : '||schema_size||' MBs .');
end;
/

注意:Prod用户总规模为:18.8125 MB。

PL/SQL过程已成功完成。

qxgroojn

qxgroojn6#

我没有为Oracle这样做过,但是在SQL Server中,您可以使用一个函数将CSV字符串转换为表,然后可以在IN子句中使用它。为Oracle重写这篇文章应该是直截了当的(我认为!)

CREATE Function dbo.CsvToInt ( @Array varchar(1000)) 
returns @IntTable table 
    (IntValue nvarchar(100))
AS
begin

    declare @separator char(1)
    set @separator = ','

    declare @separator_position int 
    declare @array_value varchar(1000) 

    set @array = @array + ','

    while patindex('%,%' , @array) <> 0 
    begin

      select @separator_position =  patindex('%,%' , @array)
      select @array_value = left(@array, @separator_position - 1)

        Insert @IntTable
        Values (Cast(@array_value as nvarchar))

      select @array = stuff(@array, 1, @separator_position, '')
    end

    return
end

然后,您可以传入CSV字符串(例如‘0001,0002,0003’)并执行如下操作

UPDATE table1 SET 
       col1 = col1 - value 
WHERE id in (SELECT * FROM csvToInt(@myParam))
mctunoxg

mctunoxg7#

AskTom网站上有一篇文章,展示了如何创建一个函数来解析CSV字符串,并以类似于给出的SQL Server示例的方式在语句中使用它。

Asktom

blpfk2vs

blpfk2vs8#

为什么它必须是存储过程?您可以通过编程方式构建预准备语句。

相关问题