【问题标题】:Pass a list of integers from C# into Oracle stored procedure将整数列表从 C# 传递到 Oracle 存储过程
【发布时间】:2014-08-10 01:53:15
【问题描述】:

我有一个 oracle 存储过程,它使用以下语句更新表。

update boxes 
set    location = 'some value'
where  boxid = passed value

我有一个页面,用户在其中选择 100 多个框并使用新的位置值更新它们。目前,我必须调用存储过程 100 多次来更新每个盒子(每次传递一个 boxid)。

我想知道如何将来自C# 的boxid 列表传递到存储过程中,这样我就必须只调用一次存储过程。

我希望在更新语句中使用 where in(boxids) 类型的 where 子句。

请告诉我如何实现这一点。提前致谢!

【问题讨论】:

标签: c# sql oracle stored-procedures


【解决方案1】:

我将创建一个新过程,旨在处理值列表。一种有效的方法是使用批量插入将多个值加载到全局临时表中,然后使用与 GTT 的连接来更新过程。

一个概念性的例子如下所示:

OracleTransaction trans = conn.BeginTransaction(IsolationLevel.RepeatableRead);
OracleCommand cmd = new OracleCommand(insertSql, conn, trans);
cmd.Parameters.Add(new OracleParameter("BOX_ID", OracleDbType.Number));
cmd.Parameters[0].Value = listOfBoxIds;   // int[] listOfBoxIds;
cmd.ExecuteArray();

OracleCommand cmd2 = new OracleCommand(storedProc, conn, trans);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.ExecuteNonQuery();

trans.Commit();

【讨论】:

    【解决方案2】:

    我理解您的担忧 - 往返行程会很费力。

    很遗憾,我没有要测试的东西,但你可以试试 Oracle bulk updates using ODP.NET

    -- edit1:如果您的提供商支持,请使用 Panagiotis Kanavos 的答案,否则请查看下方 --

    -- 由 Wernfried 突出显示的 edit12,不推荐使用 long。考虑的另一件事是最大长度 varchar2:它不能在非常大的集合上扩展。使用下面的作为最后的手段。 --

    • 将存储过程更改为接受字符串
    • 在 asktom.oracle.com 中实现 string_2_list

      create or replace type myTableType as table of varchar2 (255);
      
      create or replace function in_list( p_string in varchar2 ) return myTableType
       as
           l_string        long default p_string || ',';
           l_data          myTableType := myTableType();
           n               number;
       begin
         loop
             exit when l_string is null;
             n := instr( l_string, ',' );
             l_data.extend;
             l_data(l_data.count) := 
                   ltrim( rtrim( substr( l_string, 1, n-1 ) ) );
             l_string := substr( l_string, n+1 );
        end loop;
      
        return l_data;
      end;
      

      以上是早期变体并拼接到 varchar2,但如果您在该站点阅读更多(包括其他线程) 您会发现更高级的变体(优化、更好的异常处理)

    【讨论】:

    • Oracle 有多种集合类型,允许您传递参数列表而无需求助于字符串。
    • Oracle 数据类型 LONG 已被弃用多年!你不应该在任何新的书面代码中使用它。
    • @Wernfried:在代码下方,我建议进一步阅读原始文章以获得更高级的变体。我给出了初始版本只是因为在 SO 中不推荐仅链接答案。
    【解决方案3】:

    Oracle 允许您将值数组作为参数传递。借用this SO questionthis one,您可以像这样定义INT_ARRAY 类型:

    create or replace type CHAR_ARRAY as table of INTEGER;
    

    然后将您的存储过程定义为:

    CREATE OR REPLACE PROCEDURE product_search(
            ...
            myIds IN CHAR_ARRAY,
            ...)
    AS  
        SELECT ...
        ...
        WHERE SomeIdField IN (Select column_value FROM TABLE(myIds))
        ...
    

    然后您可以通过像这样设置OracleParameter.CollectionType 属性来传递值列表:

    OracleParameter param = new OracleParameter();
    param.OracleDbType = OracleDbType.Int32;
    param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    

    【讨论】:

    • 我认为为了正确操作,您必须在执行命令之前添加param.Size = boxids.Length;
    • @Wernfried 您还必须实际设置.Value 属性,将参数添加到Parameters 集合,编写与您传递的参数数量和名称相同的命令文本 - 无需查看我们无能为力的代码
    • @gauravthakur 发布一个新问题,其中包含您的代码、架构和特定错误。也很难理解你的意思I don't want to create it at schema level。您想在什么级别定义类型?不要在这里回答,发布一个问题来解释为什么你不想创建一个新的类型或表
    • 你为价值问题做了什么? @gs_developer_user3605534
    • @masoudvali SO 不是一个讨论论坛,对答案的 cmets 是对答案的 cmets,而不是对他人的回复。它也不是 Twitter,你不能通过将他们的名字放在评论的 end 来通知某人。什么Value problem?如果您传递了错误数量的参数,则您传递了错误数量的参数。如果您有任何问题,请发布问题
    【解决方案4】:

    您的 PL/SQL 块可能如下所示:

    CREATE OR REPLACE PACKAGE YOUR_PACKAGE AS
       TYPE TArrayOfNumber IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
       PROCEDURE Update_Boxes(boxes IN TArrayOfNumber );
    
    END YOUR_PACKAGE;
    /
    
    CREATE OR REPLACE PACKAGE BODY YOUR_PACKAGE AS
    
    PROCEDURE Update_Boxes(boxes IN TArrayOfNumber) is
    BEGIN
       FORALL i IN INDICES OF boxes 
       update boxes  
       set location = boxes(i) 
       where boxid = ...;
    END Update_Boxes;
    
    END YOUR_PACKAGE;
    

    您已经从 Panagiotis Kanavos 得到答案的 C# 代码

    【讨论】:

      猜你喜欢
      • 2011-07-29
      • 1970-01-01
      • 2012-09-24
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      • 2013-07-03
      • 2013-11-25
      • 2017-01-31
      相关资源
      最近更新 更多