【问题标题】:Oracle stored procedure with parameters for IN clause带有 IN 子句参数的 Oracle 存储过程
【发布时间】:2010-09-19 13:22:20
【问题描述】:

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

谢谢, 罗伯特

【问题讨论】:

    标签: oracle stored-procedures input plsql


    【解决方案1】:

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

    【讨论】:

    • 快速说明 - CSV 无法单独工作,因为 Oracle 会将其视为一个字符串。
    • 不应该是... from string_table(identifierList)); ...吗?
    【解决方案2】:

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

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

    很遗憾,我没有使用 .NET 环境的经验。

    【讨论】:

    • “没有直接的方法来创建参数数量可变的过程”...是的,使用 CREATE TYPE xxx AS TABLE OF yyy 然后使用该类型作为参数类型。跨度>
    • 不,这不是直接的解决方案。无论如何,您的方法是可以追溯到 2008 年的公认答案。
    • @rics 答案中的链接已失效
    【解决方案3】:

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

    Great article by Mark A. Williams

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 类似的事情可以用 PL/SQL 完成,但是将集合作为 csv 字符串传递给过程会更快。 csv 字符串需要先在 PL/SQL 中进行标记化。
        【解决方案6】:

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

        Asktom

        【讨论】:

          【解决方案7】:

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

          【讨论】:

          • 我需要在 plsql 过程中执行比“更新”更多的语句。为了举例,我稍微简化了问题。
          猜你喜欢
          • 2014-05-24
          • 2018-12-23
          • 2013-11-17
          • 2013-11-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-29
          相关资源
          最近更新 更多