在Oracle中批量收集

时间:2011-10-12 16:51:39

标签: oracle plsql oracle11g

如何查询批量收藏?如果我有

select name 
bulk collect into namesValues 
from table1

其中namesValues为dbms_sql.varchar2_table

现在,我有另一个包含

的表格XYZ
 name   is_valid
  v
  h

如果name在table1中,则我想将is_valid更新为'Y',否则为'N'。表1有1000万行。批量收集后我想执行

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

如何查询namesValue?或者还有另一种选择。表1没有索引。 请帮忙。

2 个答案:

答案 0 :(得分:5)

正如Tom Kyte(甲骨文公司副总裁)所说:

  

我的口头禅,我会非常感谢你,是:

     

如果可能,您应该在单个SQL语句中执行此操作。

     

如果您无法在单个SQL语句中执行此操作,请在PL / SQL中执行此操作。

     

如果您无法在PL / SQL中执行此操作,请尝试使用Java存储过程。

     

如果您不能在Java中执行此操作,请在C外部过程中执行此操作。

     

如果您不能在C外部例程中执行此操作,则可能需要   认真思考为什么你需要这样做......

     

想一下......

     

学习所有有关SQL的知识......

如果可以,您应该在SQL中执行更新。如果您需要添加索引来执行此操作,那么循环使用BULK COLLECT填充的集合可能更为可取。

但是,如果这是某种任务...... 你应该这样指定它,但是你可以这样做。

我假设你的数据库服务器没有能力在内存中容纳1000万条记录,所以不是BULK一次性收集所有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表很大且名称列上没有索引,您的更新仍会导致问题。

希望它有所帮助...

答案 1 :(得分:4)

  

“Table1没有索引。”

那里有你的问题。为什么不?在TABLE1.NAME上放置一个索引,并使用普通的SQL UPDATE来修改XYZ中的数据。

尝试使用批量收集解决此问题不是正确的方法。