我有一个oracle存储过程,它使用以下语句更新表。
update boxes
set location = 'some value'
where boxid = passed value
我有一个页面,用户可以选择100多个框并使用新的位置值更新它们。目前,我必须多次调用存储过程来更新每个框(通过每次传递一个boxid)。
我想知道如何将C#
中的boxid列表传递到存储过程中,以便我只需要调用一次存储过程。
我希望在更新语句中使用 where(boxids)种类的where子句。
请让我知道如何实现这一目标。提前谢谢!
答案 0 :(得分:5)
Oracle允许您将值数组作为参数传递。借用this SO question和this 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#代码