Массовый сбор PL / SQL в ассоциативный массив с разреженным ключом - PullRequest
10 голосов
/ 26 апреля 2010

Я хочу выполнить SQL-запрос внутри PL / SQL и заполнить результаты в ассоциативный массив, где один из столбцов в SQL становится ключом в ассоциативном массиве. Например, скажем, у меня есть таблица Person со столбцами

PERSON_ID   INTEGER      PRIMARY KEY
PERSON_NAME VARCHAR2(50)

... и такие значения, как:

 PERSON_ID  |  PERSON_NAME
 ------------------------
 6          |  Alice
 15         |  Bob
 1234       |  Carol

Я хочу собрать эту таблицу в TABLE OF VARCHAR2(50) INDEX BY INTEGER так, чтобы ключ 6 в этом ассоциативном массиве имел значение Alice и так далее. Можно ли это сделать в PL / SQL? Если да, то как?

Ответы [ 2 ]

14 голосов
/ 26 апреля 2010

Нет, вы должны использовать либо 2 коллекции (id, name), либо одну, тип элемента которой является записью.

Вот пример последнего:

  cursor getPersonsCursor is
    SELECT ID, Name
    FROM   Persons
    WHERE  ...;

  subtype TPerson is getPersonsCursor%rowtype;
  type TPersonList is table of TPerson;
  persons TPersonList;
begin

open getPersonsCursor;
fetch getPersonsCursor
  bulk collect into persons;
close getPersonsCursor;

if persons.Count > 0 then
  for i in persons.First .. persons.Last loop
    yourAssocArray(persons(i).ID) := persons(i).Name;
  end loop;
end if;
6 голосов
/ 26 апреля 2010

Если мы хотим указать значение в индексе ассоциативного массива, мы должны использовать этот синтаксис:

SQL> declare
  2      type n_array is table of varchar2(30)
  3           index by binary_integer;
  4      emp_names n_array;
  5  begin
  6      for r in ( select ename, empno from emp )
  7      loop
  8          emp_names(r.empno) := r.ename;
  9      end loop;
 10
 11      dbms_output.put_line('count='||emp_names.count()
 12                               ||'::last='||emp_names.last());
 13      dbms_output.put_line(emp_names(8085));
 14
 15  end;
 16  /
count=19::last=8085
TRICHLER

PL/SQL procedure successfully completed.

SQL>

Мы можем заполнить ассоциативные массивы массовым сбором, но только если индекс является целым числом, и мы рады индексировать (неявным) ROWNUM, т.е. не разреженным ключом ...

SQL> declare
  2      type n_array is table of varchar2(30)
  3           index by binary_integer;
  4      emp_names n_array;
  5  begin
  6      select ename
  7      bulk collect into emp_names
  8      from emp ;
  9
 10      dbms_output.put_line('count='||emp_names.count()
 11                               ||'::last='||emp_names.last());
 12      dbms_output.put_line(emp_names(19));
 13
 14  end;
 15  /
count=19::last=19
FEUERSTEIN

PL/SQL procedure successfully completed.

SQL>

Если честно, если вам нужно использовать BULK COLLECT, вы, вероятно, имеете дело с большим количеством данных, чем уместно для ассоциативного массива.

Редактировать

Дешевый тест производительности двух подходов:

SQL> declare
  2      type n_array is table of varchar2(30)
  3           index by binary_integer;
  4      emp_names n_array;
  5      s_time pls_integer;
  6      e_time pls_integer;
  7  begin
  8      s_time := dbms_utility.get_time;
  9      select ename
 10      bulk collect into emp_names
 11      from big_emp
 12      where rownum <= 500;
 13      dbms_output.put_line('bulk collect elapsed time = '
 14                              ||to_char(dbms_utility.get_time - s_time));
 15      s_time := dbms_utility.get_time;
 16      for r in ( select ename, empno from big_emp
 17                 where rownum <= 500 )
 18      loop
 19          emp_names(r.empno) := r.ename;
 20      end loop;
 21      dbms_output.put_line('sparse array elapsed time = '
 22                              ||to_char(dbms_utility.get_time - s_time));
 23  end;
 24  /

bulk collect elapsed time = 0
sparse array elapsed time = 0

PL/SQL procedure successfully completed.

SQL>

Тесты производительности настенных часов печально известны. Но для нескольких сотен записей вряд ли стоит беспокоиться о какой-либо разнице, особенно в контексте того места, где мы могли бы использовать ассоциативный массив.

Редактировать 2

@ Дэн сказал:

мне кажется, что желающий запросить порядочное количество рядов в структура данных, которая может быть использована для поиск в постоянном времени должен быть довольно общая потребность

Это действительно зависит от вашего определения «приличного размера числа». Неужели так много случаев, когда мы хотим заполнить ассоциативный массив тысячами строк с индексом строки? Когда мы добираемся до этих видов чисел, обычная таблица базы данных может быть столь же полезной, особенно в 11g Enterprise Edition с кэшированием набора результатов .

...