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

时间:2008-10-28 10:19:54

标签: oracle stored-procedures input plsql

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

谢谢, 罗伯特

7 个答案:

答案 0 :(得分:26)

使用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开发人员遇到这个问题。

答案 1 :(得分:2)

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

Great article by Mark A. Williams

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:-1)

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

答案 5 :(得分:-1)

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

答案 6 :(得分:-1)

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

请参阅Asktom