将C#中的整数列表传递给Oracle存储过程

时间:2014-06-19 13:42:27

标签: c# sql oracle stored-procedures

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

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

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

我想知道如何将C#中的boxid列表传递到存储过程中,以便我只需要调用一次存储过程。

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

请让我知道如何实现这一目标。提前谢谢!

4 个答案:

答案 0 :(得分:5)

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;

答案 1 :(得分: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 :(得分:0)

我理解您的担忧 - 往返旅行将会产生负担。

不幸的是我没有什么可以测试,但你可以试试 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,但是如果你在那个站点读了更多(包括其他线程) 你会发现更高级的变种(优化,更好的异常处理)

答案 3 :(得分:0)

您的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#代码