навалом собрать в оракуле - PullRequest
2 голосов
/ 12 октября 2011

Как запросить массовую коллекцию? Если, например, у меня есть

select name 
bulk collect into namesValues 
from table1

где namesValues ​​dbms_sql.varchar2_table.

Теперь у меня есть еще одна таблица XYZ, которая содержит

 name   is_valid
  v
  h

Я хочу обновить is_valid до 'Y', если имя в таблице1, иначе 'N' Таблица1 имеет 10 миллионов строк. После массового сбора хочу выполнить

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

Как запросить namesValue? Или есть другой вариант. Таблица1 не имеет индекса. пожалуйста, помогите.

Ответы [ 2 ]

5 голосов
/ 13 октября 2011

Как говорит Том Кайт (вице-президент Oracle Corp.):

Моя мантра, которой я буду придерживаться большое спасибо:

Вы должны сделать это в одном операторе SQL, если это вообще возможно.

Если вы не можете сделать это в одном операторе SQL, сделайте это в PL / SQL.

Если вы не можете сделать это в PL / SQL, попробуйте хранимую процедуру Java.

Если вы не можете сделать это в Java, сделайте это во внешней процедуре C.

Если вы не можете сделать это во внешней подпрограмме C, вы можете захотеть всерьез задумайтесь о том, зачем вам это нужно…

мыслить в наборах ...

узнать все, что можно узнать о SQL ...

Вы должны выполнить свое обновление в SQL, если можете. Если вам нужно добавить индекс, чтобы сделать это, то это может быть предпочтительнее, чем цикл по коллекции, заполненной BULK COLLECT.

Если, однако, это какое-то задание .... Вы должны указать это как таковое, но вот как вы это сделаете.

Я предположил, что у вашего сервера БД нет возможности хранить 10 миллионов записей в памяти, поэтому вместо ОБЪЕМНОГО СОБИРАТЬ все 10 миллионов записей за один раз я поместил ОБЪЕМНЫЙ СБОР в цикл, чтобы уменьшить нагрузку на память. Если это не так, то вы можете пропустить цикл массового сбора.

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;
/

В зависимости от размеров сегментов отката и т. Д. Вы можете захотеть выполнить временные коммиты в цикле массового сбора, но имейте в виду, что вы не сможете откатить эти изменения. Я намеренно не добавил к нему никаких коммитов, чтобы вы могли выбрать, где их разместить в соответствии с вашей системой.

Вы также можете изменить размер константы c_bulk_limit в зависимости от доступных вам ресурсов.

Ваше обновление будет вызывать проблемы, если таблица xyz велика и в столбце имени нет индекса.

Надеюсь, это поможет ...

4 голосов
/ 12 октября 2011

"Таблица1 не имеет индекса."

Что ж, тут есть ваша проблема.Почему бы и нет?Поместите индекс в TABLE1.NAME и используйте обычное ОБНОВЛЕНИЕ SQL для исправления данных в XYZ.

Попытка решить эту проблему с массовым сбором не является правильным подходом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...