Объявление и заполнение индекса ассоциативного массива

При написании программы появилась необходимость в создании ассоциативного массива с использованием индекса, в связи с этим есть несколько вопросов:

Правильно понимаю, что при объявлении индекса тип данных может быть только varchar2, BINARY_INTEGER, PLS_INTEGER, никаких integer и number?

Допустим, я объявил для массива индекс index by SALE_TRANS.Player_Info%type, затем в теле программы я заполняю массив данными:

select
     Player_Info(varchar2),
     id (number),
     trns(integer),
     email(varchar2) bulk collect into happy
from SALE_TRANS t
where t.Trns_ID = 2497170`

Индекс автоматически создастся по столбцу Player_Info?

Если я объявляю индекс index by VARCHAR2(3333), то при заполнении массива:

select
     Player_Info(varchar2),
     id (number),
     trns(integer),
     email(varchar2) bulk collect into happy
from SALE_TRANS t
where t.Trns_ID = 2497170

То индекс создастся на каком столбце?


Ответы (2 шт):

Автор решения: dtroyan
  1. Да, верно.

2,3. Bulk Collect не работает с ассоциативными массивами, кроме индексированых pls_integer. Если pls_integer, то вам надо указывать отдельные поля:

SELECT employee_id, last_name 
    BULK COLLECT INTO   enums, names
    FROM   employees
→ Ссылка
Автор решения: 0xdb

Посмотрим, что говорит об ассоциативных коллекциях оф.источники (выделил жирным то, что надо обязательно понять и усвоить):

An associative array (formerly called PL/SQL table or index-by table) is a set of key-value pairs. Each key is a unique index, used to locate the associated value with the syntax variable_name(index).

The data type of index can be either a string type (VARCHAR2, VARCHAR, STRING, or LONG) or PLS_INTEGER. Indexes are stored in sort order, not creation order.

То есть, лучше представить, что ассоциативные коллекции это упорядоченный по уникальному ключу набор значений, чем индексированный набор значений.

В SQL запросах могут использоваться только ассоциативные коллекции с типом ключа - PLS_INTEGER. При этом, текущему ключу будет присвоено значение не какого-либо столбца, а именно порядковый номер записи в результирующем наборе (result set). То ест, это всегда и без исключений последовательность без пропусков - 1..N (отсюда и устаревшее название - index by table).

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


В заключениe, несколько воспроизводимых примеров (на db<>fiddle). Подготовка схемы:

create table t (id, memo, created) as
    select rownum, 'memo '||lpad (rownum, 4, '0'), sysdate
    from dual connect by level<=3;
/
create or replace package pack as
    type rec is record (id int, memo varchar2 (96), created date default sysdate);
    type arrbynum is table of t%rowtype index by pls_integer;
    type arrbykey is table of t%rowtype index by varchar2 (32);
end;
/

В SQL запросах не могут быть использованы ассоциативные коллекции с символьным типом ключа:

declare k pack.arrbykey;
begin
    select * bulk collect into k from t;
end;
/

PLS-00657: Implementation restriction: bulk SQL with associative arrays with VARCHAR2 key is not supported.

Функционал в #1 и #2 полностью эквивалентен, #2 поясняет, что делает "под капотом" #1:

declare
    n pack.arrbynum;
    rc sys_refcursor;
    rec t%rowtype;
begin
    --#1
    select * bulk collect into n from t;
    --#2
    open rc for select * from t;
    loop fetch rc into rec;
        exit when rc%notfound;
        n(rc%rowcount) := rec; 
    end loop;
end;
/

Инициализацию ассоциативной коллекции данными из SQL запроса можно выполнить так:

declare 
    k pack.arrbykey;
    key char (8);
begin
    for r in (select * from t) loop
        key := 'code'||lpad (r.id, 4, '0');
        k (key) := r;
    end loop;
end;
/
→ Ссылка