Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Добрый день! В таблице SCHEMA_NAME.TABLE_NAME есть 10000 значений. Нужно их порциями по 100 штук копировать в список, производить какие-то действия с ним и замерять время для каждых 100 значений. Мне представляется такой вариант:

DECLARE
  l_VPUSubList   SYS.ODCINUMBERLIST;
  l_TotalVPUList SYS.ODCINUMBERLIST;
  indSub   INTEGER;   indTotal INTEGER;
  start_time TIMESTAMP WITH TIME ZONE;
  end_time TIMESTAMP WITH TIME ZONE;
  exec_length INTERVAL DAY TO SECOND;
BEGIN
  select VPU_NUM 
  BULK COLLECT INTO l_TotalVPUList
  from SCHEMA_NAME.TABLE_NAME
  
  indSub := 1; indTotal := 1;
  WHILE indTotal <= l_TotalVPUList.LAST
  LOOP
    --dbms_output.put_line (ind);
    l_VPUSubList(indSub) := l_TotalVPUList(indTotal);
    indSub := indSub + 1; indTotal := indTotal + 1;
    IF MOD (indTotal, 100) = 0 -- Каждые 100 значений
    THEN
      start_time := SYSTIMESTAMP;
      --Здесь какие-то действия с этими 100 значений
      end_time := SYSTIMESTAMP;
      exec_length := end_time - start_time;
      dbms_output.put_line('Длина в формате дни часы:минуты:секунды: '||exec_length);
    END IF;
  END LOOP;  
END;


Но при попытке запуска скрипта возниакет ошибка:
ORA-06531: Ссылка на неинициализированный набор
ORA-06512: на line 18


Как избавиться от неё или как более эффективно написать скрипт?
8 ноя 18, 16:13    [21728361]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16844
ultrasonic7
Как избавиться от неё или как более эффективно написать скрипт?

1. bulk collect имеет кляузу LIMIT.
2. Изложите цикл в виде
for i in 1.. l_TotalVPUList.count loop

Это избавит от необходимости отдельно обрабатывать случай пустой коллекции, с которым Вы столкнулись.
8 ноя 18, 16:19    [21728366]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 17887
Я думаю, что тут столкнулись с
ultrasonic7
...
    l_VPUSubList(indSub) := l_TotalVPUList(indTotal);

8 ноя 18, 16:20    [21728370]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
-2-
Member

Откуда:
Сообщений: 13960
ultrasonic7
Как избавиться от неё
поставить return после begin, потому как очевидного решения, инициализировать переменную, будет недостаточно, чтобы избежать последующих ошибок.
ultrasonic7
как более эффективно написать скрипт?
курсор + limit 100
8 ноя 18, 16:21    [21728372]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16844
andrey_anonymous
случай пустой коллекции, с которым Вы столкнулись.

Слишком по диагонали смотрел, сорри.
Вот это:
l_VPUSubList   SYS.ODCINUMBERLIST;

надо инициализировать и расширять руками.
Лучше объявите ассоциативный массив.
8 ноя 18, 16:23    [21728374]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 9172
ultrasonic7
Как избавиться


DECLARE
  l_VPUSubList   SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
  l_TotalVPUList SYS.ODCINUMBERLIST;
  indSub   INTEGER;   indTotal INTEGER;
  start_time TIMESTAMP WITH TIME ZONE;
  end_time TIMESTAMP WITH TIME ZONE;
  exec_length INTERVAL DAY TO SECOND;
BEGIN
  select VPU_NUM 
  BULK COLLECT INTO l_TotalVPUList
  from SCHEMA_NAME.TABLE_NAME
  
  indSub := 1; indTotal := 1;
  l_VPUSubList.extend(l_TotalVPUList.LAST);
  WHILE indTotal <= l_TotalVPUList.LAST
  LOOP
    --dbms_output.put_line (ind);
    l_VPUSubList(indSub) := l_TotalVPUList(indTotal);
    indSub := indSub + 1; indTotal := indTotal + 1;
    IF MOD (indTotal, 100) = 0 -- Каждые 100 значений
    THEN
      start_time := SYSTIMESTAMP;
      --Здесь какие-то действия с этими 100 значений
      end_time := SYSTIMESTAMP;
      exec_length := end_time - start_time;
      dbms_output.put_line('Длина в формате дни часы:минуты:секунды: '||exec_length);
    END IF;
  END LOOP;  
END;


SY
8 ноя 18, 16:24    [21728375]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Суть в том, что l_VPUSubList должен быть именно типа SYS.ODCINUMBERLIST и содержать 100 элементов.
То, что список надо расширить
l_VPUSubList.extend(l_TotalVPUList.LAST);

понятно. Но l_TotalVPUList.LAST содержит 10000 значений, а мне нужно копировать в l_VPUSubList порциями по 100 и для каждой итерации цикла вызывать процедуру, у которой входной параметр SYS.ODCINUMBERLIST и условия запуска требуют, чтобы в нём было 100 значений.
Не проще ли будет один раз расширить l_VPUSubList на 100 элементов?
l_VPUSubList.extend(100);
9 ноя 18, 10:28    [21729062]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Нет, проверил, такой вариант не подходит. В этом случае индекс выходит за пределы счетчика массива. Нужно каждый раз копировать перезаписывать прежние 100 значений в l_VPUSubList следующими 100 значениями из l_TotalVPUList.
9 ноя 18, 10:37    [21729076]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром продолжается. КЯЗ
Сообщений: 28396
ultrasonic7
проще
andrey_anonymous
кляузу LIMIT
9 ноя 18, 10:38    [21729078]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Хотел написать не "копировать", а "перезаписывать"
9 ноя 18, 10:40    [21729080]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 1371
ultrasonic7
Нет, проверил, такой вариант не подходит. В этом случае индекс выходит за пределы счетчика массива. Нужно каждый раз копировать перезаписывать прежние 100 значений в l_VPUSubList следующими 100 значениями из l_TotalVPUList.


каждые 100 записей indSub надо сбрасывать indSub:=1;

ps
к-во записей всегда кратно 100?

.....
stax
9 ноя 18, 11:01    [21729111]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Stax
к-во записей всегда кратно 100?

Да.
9 ноя 18, 12:06    [21729233]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 1371
ultrasonic7
Stax
к-во записей всегда кратно 100?

Да.


есть мнение что Вы обрабатываете не 100, а 99 записей (indTotal := indTotal + 1; IF MOD (indTotal, 100) = 0 -- Каждые 100 значений)

зы
повторно, в IF счетчик надо сбрасывать

.....
stax
9 ноя 18, 12:36    [21729303]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Stax
повторно, в IF счетчик надо сбрасывать
.....
stax

Да, надо это учесть.
9 ноя 18, 14:38    [21729599]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16844
Утомительная какая-то тема.
+
DECLARE
  cursor c_data is -- тут запрос к данным
    select ROWNUM  VPU_NUM 
      from dual connect by level < 1000;

  type t_numtbl is table of c_data%rowtype index by pls_integer;
  l_VPUList t_numtbl;

  c_batch_size constant integer := 100; -- размер пачки
  start_time TIMESTAMP(6);
  exec_length INTERVAL DAY TO SECOND;

BEGIN
  open c_data;
  loop
    fetch c_data bulk collect into l_VPUList limit c_batch_size;
    start_time := SYSTIMESTAMP;
    for i in 1..l_VPUList.count() loop
      --Здесь какие-то действия с этими 100 значений
      null;
    end loop;
    exec_length := SYSTIMESTAMP - start_time;
    dbms_output.put_line('Обработано '||l_VPUList.count||' элементов; Продолжительность обработки: '||exec_length);
  exit when l_VPUList.count < c_batch_size;
  end loop;  
END;
9 ноя 18, 15:07    [21729672]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 1371
andrey_anonymous,

    for i in 1..l_VPUList.count() loop
    end loop;

не нужен

....
stax
9 ноя 18, 15:16    [21729688]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16844
Stax
andrey_anonymous,

    for i in 1..l_VPUList.count() loop
    end loop;

не нужен

Там "какие-то действия", а ТС цикл по коллекции формирует как Бог на душу положит - вылетит опять за границы, напишет нам "случилась ошибка" - гадай потом...
9 ноя 18, 15:19    [21729692]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 1371
andrey_anonymous
Там "какие-то действия",


автор
а мне нужно копировать в l_VPUSubList порциями по 100 и для каждой итерации цикла вызывать процедуру, у которой входной параметр SYS.ODCINUMBERLIST и условия запуска требуют, чтобы в нём было 100 значений.


.....
stax
9 ноя 18, 15:23    [21729702]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16844
Stax
andrey_anonymous
Там "какие-то действия",

автор
входной параметр SYS.ODCINUMBERLIST и условия запуска требуют, чтобы в нём было 100 значений.


Просмотрел.
Надо тогда тип коллекции обратно поменять :)
9 ноя 18, 15:33    [21729731]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
В результате сделал так. Фетч происходит прямо в SYS.ODCINUMBERLIST, а внутренний цикл получается ненужным.
DECLARE
  cursor c_data is -- тут запрос к данным
    select VPU_NUM 
    from SCHEMA_NAME.TABLE_NAME;

  l_VPUList SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();

  c_batch_size constant integer := 100; -- размер пачки
  start_time TIMESTAMP WITH TIME ZONE;
  total_start_time TIMESTAMP WITH TIME ZONE;
  exec_length INTERVAL DAY TO SECOND;
  total_exec_length INTERVAL DAY TO SECOND;

BEGIN
  l_VPUList.extend(c_batch_size);
  total_start_time := SYSTIMESTAMP;
  open c_data;
  loop
    fetch c_data bulk collect into l_VPUList limit c_batch_size;
    start_time := SYSTIMESTAMP;
    SCHEMA_NAME.PACKAGE_NAME.PROC_NAME(param_in => l_VPUList);
    exec_length := SYSTIMESTAMP - start_time;
    dbms_output.put_line('Обработано '||l_VPUList.count||' элементов; Продолжительность обработки - часы:минуты:секунды: '||exec_length);
  exit when l_VPUList.count < c_batch_size;
  end loop;
  total_exec_length := SYSTIMESTAMP - total_start_time;
  dbms_output.put_line('Общая продолжительность обработки - часы:минуты:секунды: '||total_exec_length);  
END;
12 ноя 18, 09:55    [21731425]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Спасибо всем ответившим.
12 ноя 18, 10:00    [21731430]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
Stax
Member

Откуда: Ukraine,Lviv
Сообщений: 1371
ultrasonic7,

SCHEMA_NAME.PACKAGE_NAME.PROC_NAME(param_in => l_VPUList); может отработать на пустой набор

.....
stax
12 ноя 18, 13:23    [21731726]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Stax,
Да, есть такое. После обработки последних 100 элементов из 10000:
Обработано 100 элементов; Продолжительность обработки - часы:минуты:секунды: +00 00:00:00.210193

обрабатывается 0 элементов:
Обработано 0 элементов; Продолжительность обработки - часы:минуты:секунды: +00 00:00:00.007318

Какую проверку добавить, чтобы список из 0 элементов не обрабатывался?
Так не помогает:
IF l_VPUList IS NOT NULL THEN
      SOME_PROC(iDocIDs => l_VPUList);

так тоже:
IF l_VPUList.COUNT > 0 THEN
      SOME_PROC(iDocIDs => l_VPUList);
вчера, 15:00    [21733073]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
так тоже не помогает
IF c_data%ROWCOUNT > 0 THEN
вчера, 15:05    [21733081]     Ответить | Цитировать Сообщить модератору
 Re: Копирование списков порциями  [new]
ultrasonic7
Member

Откуда:
Сообщений: 92
Сам себе ответил. Надо было сделать так:
DECLARE
  cursor c_data is
    select VPU_NUM 
    from SCHEMA_NAME.TABLE_NAME;

  l_VPUList SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();

  c_batch_size constant integer := 100; -- размер пачки
  start_time TIMESTAMP WITH TIME ZONE;
  total_start_time TIMESTAMP WITH TIME ZONE;
  exec_length INTERVAL DAY TO SECOND;
  total_exec_length INTERVAL DAY TO SECOND;

BEGIN
  l_VPUList.extend(c_batch_size);
  total_start_time := SYSTIMESTAMP;
  open c_data;
  loop
    fetch c_data bulk collect into l_VPUList limit c_batch_size;
    IF c_data%FOUND THEN
      start_time := SYSTIMESTAMP;
      SCHEMA_NAME.PACKAGE_NAME.PROC_NAME(param_in => l_VPUList);
      COMMIT;
      exec_length := SYSTIMESTAMP - start_time;
      dbms_output.put_line('Обработано '||l_VPUList.count||' элементов; Продолжительность обработки - часы:минуты:секунды: '||exec_length);
    END IF;
  exit when l_VPUList.count < c_batch_size;
  end loop;
  total_exec_length := SYSTIMESTAMP - total_start_time;
  close c_data;
  dbms_output.put_line('Общая продолжительность обработки - часы:минуты:секунды: '||total_exec_length);  
END;
вчера, 15:17    [21733106]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Oracle Ответить