2011-10-12 56 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表很大,名称列上没有索引,则更新仍会导致问题。

希望它可以帮助...