如何创建一个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功能兼容。

谢谢, 罗伯特

有帮助吗?

解决方案

使用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 来实现直接从这些类型映射到相应的Java对象。我快速浏览了一下,但是我看不到C#的直接等价物。我以为我会提到它,以防Java开发人员遇到这个问题。

其他提示

我找到了Mark A. Williams的以下文章,我认为这篇文章对这个帖子很有用。本文提供了一个使用关联数组将数组从C#传递到PL / SQL过程的一个很好的示例(TYPE myType IS TABLE OF mytable.row%TYPE INDEX BY PLS_INTEGER):

Mark A. Williams的精彩文章

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

  1. 如果有一些典型的调用类型,过程可能会有所帮助。
  2. 如果参数数量有一个上限(并且它们的类型也是预先知道的),参数的默认值可能会有所帮助。
  3. 最好的选择可能是使用游标变量,这是指向数据库游标的指针。
  4. 不幸的是,我没有.NET环境的经验。

为什么不使用长参数列表并将值加载到表构造函数中?这是这个技巧的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);

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

我没有为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)) 

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

参见 Asktom

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top