2011-10-12 76 views
2

如何查詢批量收集?如果例如我有在oracle中批量收集

select name 
bulk collect into namesValues 
from table1 

其中namesValues是dbms_sql.varchar2_table

現在,我有另一個表XYZ包含

name is_valid 
    v 
    h 

我想更新is_valid爲 'Y',如果名稱爲其他table1的 'N'。表1有1000萬行。批量收集後我想執行

update xyz 
set is_valid ='Y' 
where name in namesValue. 

如何查詢namesValue?或者還有另一種選擇。表1沒有索引。 請幫忙。

+1

參見:http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/statements_10002.htm#sthref6770,尤其是有鏈接的例子。 –

回答

4

「Table1沒有索引」。

那麼你的問題就在那裏。爲什麼不?將一個索引放在TABLE1.NAME上,並使用正常的SQL UPDATE修改XYZ中的數據。

試圖用批量收集來解決這個問題不是正確的方法。

5

當湯姆凱特(Oracle公司副總裁)說:

我的口頭禪,那我將要堅持非常感謝你,是:

你應該做它在一個單一的SQL語句如果可能的話。

如果您不能在單個SQL語句中執行此操作,請在PL/SQL中執行此操作。

如果您不能在PL/SQL中執行此操作,請嘗試Java存儲過程。

如果你不能用Java來完成,那麼在C外部程序中執行它。

如果你不能在C外部例程做到這一點,你可能要 認真想想爲什麼它是你需要做...

想套...

學習一切有了解SQL ...

如果可以的話,您應該在SQL中執行更新。如果你需要添加一個索引來做到這一點,那麼最好循環使用BULK COLLECT填充的集合。

但是,如果這是某種分配...... 您應該這樣指定,但以下是您要如何操作的方法。

我假設你的數據庫服務器沒有能力在內存中容納1000萬條記錄,而不是龐大地收集所有1000萬條記錄。我已經把BULK COLLECT放入循環以減少你的內存開銷。如果情況並非如此,則可以省略批量收集循環。

DECLARE 
    c_bulk_limit CONSTANT PLS_INTEGER := 500000; 
    -- 
    CURSOR names_cur 
    IS 
     SELECT name 
     FROM table1; 
    -- 
    TYPE namesValuesType IS TABLE OF table1.name%TYPE 
     INDEX BY PLS_INTEGER; 
    namesValues namesValuesType; 
BEGIN 

    -- Populate the collection 
    OPEN name_cur; 
    LOOP 
     -- Fetch the records in a loop limiting them 
     -- to the c_bulk_limit amount at a time 
     FETCH name_cur BULK COLLECT INTO namesValues 
     LIMIT c_bulk_limit; 

     -- Process the records in your collection 
     FORALL x IN INDICES OF namesValues 
     UPDATE xyz 
      SET is_valid ='Y' 
      WHERE name = namesValue(x) 
      AND is_valid != 'Y'; 

     -- Set up loop exit criteria 
     EXIT WHEN namesValues.COUNT < c_bulk_limit; 
    END LOOP; 
    CLOSE name_cur; 

    -- You want to update all remaining rows to 'N' 
    UPDATE xyz 
     SET is_valid ='N' 
    WHERE is_valid IS NULL; 

EXCEPTION 
    WHEN others 
    THEN 
     IF name_cur%ISOPEN 
     THEN 
     CLOSE name_cur; 
     END IF; 
     -- Re-raise the exception; 
     RAISE; 
END; 
/

根據您的回滾段大小等,你可能希望將大宗內發佈臨時提交收集循環,但要知道,你不會再能回滾這些變化。我故意沒有添加任何COMMIT,所以你可以選擇把它們放在哪裏以適應你的系統。

您還可能想要根據可用資源更改c_bulk_limit常量的大小。

如果xyz表很大,名稱列上沒有索引,則更新仍會導致問題。

希望它可以幫助...