2014-06-19 32 views
1

我有一個oracle存儲過程,它使用以下語句更新表。將來自C#的整數列表傳遞到Oracle存儲過程

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

我有一個頁面,用戶選擇100多個盒子並用新的位置值更新它們。目前,我必須調用存儲過程100次以更新每個盒子(每次傳遞boxid)。

我想知道如何將C#中的boxids列表傳遞給存儲過程,以便我只需調用存儲過程一次。

我希望能使用其中在(boxids)種更新語句中的where子句。

請讓我知道如何做到這一點。提前致謝!

+0

http://stackoverflow.com/questions/11508240/how-can-i-supply-a-listint-to-a-sql - 參數 – Habib

+0

http://stackoverflow.com/questions/4032006/passing-an-array-from-net-application-to-oracle-stored-procedure?rq=1 –

+0

您使用的是哪種ADO.NET提供程序?如果提供商支持,您可以將數字作爲數組傳遞。 Oracle確實支持數組參數,請檢查[this SO question](http://stackoverflow.com/questions/15515772/array-in-in-clause-oracle-plsql)關於如何傳遞值列表以及適當的' IN'查詢 –

回答

4

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; 
+0

爲TVP +1,因爲我不知道他們的存在。 – Christos

+0

CollectionType的+1 - 不知道。 – GangBunTu

+0

@Panagiotis謝謝你的回答。我怎樣才能給參數賦值。我收到錯誤否或參數類型錯誤。 – Deepak

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(); 
+0

+1 ExecuteArray - 不知道。 – GangBunTu

0

我理解你的關切 - 的往返將被徵稅。

不幸的是我沒有什麼可考,但你可以嘗試 Oracle bulk updates using ODP.NET

- EDIT1:與帕納約蒂斯Kanavos的答案去如果您的提供商支持的話,否則下面的檢查 -

- 作爲Wernfried突出顯示的edit12,已被棄用。另一個要考慮的問題是最大長度varchar2:它不能在一個很大的集合上進行縮放。使用下面的一個作爲最後的手段。 -

  • 改變你的存儲過程來接受字符串
  • 實施string_2_list在asktom.oracle.com。

    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,但如果你讀更多的在該網站 你會發現更高級的變體(包括其它線程)(優化,更好的異常處理)

+0

Oracle具有多種集合類型,允許您傳遞參數列表而不使用字符串。 –

+0

Oracle數據類型'LONG'已經過很長時間了!你不應該在任何新的書面代碼中使用它。 –

+0

@ Wernfried:在我建議閱讀原始文章的代碼之下,以獲得更高級的變體。我給出了最初的版本,因爲SO中不推薦使用僅鏈接的答案。 – GangBunTu

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; 

的C#代碼,你從帕納約蒂斯Kanavos已經得到回答

相關問題