PL/SQL: выбор из таблицы в массив-ассоциированный элемент

Я пытаюсь выбрать данные в ассоциативный массив pl/sql в одном запросе. Я знаю, что могу сделать это с помощью жестко закодированного ключа, но мне хотелось узнать, есть ли способ связать другой столбец (ключевой столбец).


DECLARE
TYPE VarAssoc IS TABLE OF varchar2(2) INDEX BY varchar2(3);
vars VarAssoc;
BEGIN
SELECT foo, bar INTO vars(foo) FROM schema.table;
END;

Я получаю сообщение об ошибке: foo должен быть объявлен, когда я это делаю. Есть ли способ создать мой ассоциированный массив в одном запросе или мне нужно вернуться в цикл FOR?

Ответы

Ответ 1

Просто прокомментируйте ответ APC, похоже, вы сами это поняли. Но я решил, что отвечу в любом случае для будущих искателей.

Это более простой код, но не имеет преимущества скорости использования BULK COLLECT. Просто зациклируйте строки, возвращаемые запросом, и установите элементы в ассоциативном массиве индивидуально.

DECLARE
  TYPE VarAssoc IS TABLE OF varchar2(200) INDEX BY varchar2(30);
  vars VarAssoc;
BEGIN
  FOR r IN (SELECT table_name,tablespace_name FROM user_tables) LOOP
    vars(r.table_name) := r.tablespace_name;
  END LOOP;

  dbms_output.put_line( vars('JAVA$OPTIONS') );
END;

Ответ 2

Это было бы аккуратно, если бы это было возможно, но это не простой способ добиться этого.

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

Учитывая данные теста...

SQL> select * from t23
  2  order by c1
  3  /

C1 C2
-- ---
AA ABC
BB BED
CC CAR
DD DYE
EE EYE
ZZ ZOO

6 rows selected.

SQL>

... мы можем заполнить ассоциативный массив в два этапа:

SQL> set serveroutput on
SQL>
SQL> declare
  2      type varassoc is table of varchar2(3) index by varchar2(2);
  3      vars varassoc;
  4
  5      type nt is table of t23%rowtype;
  6      loc_nt nt;
  7
  8  begin
  9      select * bulk collect into loc_nt from t23;
 10      dbms_output.put_line('no of recs = '||sql%rowcount);
 11
 12      for i in loc_nt.first()..loc_nt.last()
 13      loop
 14          vars(loc_nt(i).c1) := loc_nt(i).c2;
 15      end loop;
 16
 17      dbms_output.put_line('no of vars = '||vars.count());
 18
 19      dbms_output.put_line('ZZ = '||vars('ZZ'));
 20
 21  end;
 22  /
no of recs = 6
no of vars = 6
ZZ = ZOO

PL/SQL procedure successfully completed.

SQL>

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

Ответ 3

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

Если да, рассмотрели ли вы это внедрение как тип коллекции?

например.

CREATE OR REPLACE TYPE VAR_ASSOC as OBJECT(
  KEYID   VARCHAR2(3),
  DATAVAL VARCHAR2(2)
)
/

CREATE OR REPLACE TYPE VAR_ASSOC_TBL AS TABLE OF VAR_ASSOC
/

CREATE OR REPLACE PROCEDURE USE_VAR_ASSOC_TBL
AS
  vars Var_Assoc_tbl; 
  -- other variables...
BEGIN 
    select cast ( multiset (
                        select foo as keyid,
                               bar as dataval
                        from   schema.table
                           ) as var_Assoc_tbl
                )
     into vars
     from dual;   
     -- and later, when you want to do your lookups
     select  ot.newfoo 
            ,myvars.dataval
            ,ot.otherval
     into   ....       
     from   schema.other_Table ot
     join   table(vars) as myvars
     on     ot.newfoo = myvars.keyid;
end;
/     

Это дает вам поиск по значению символьного ключа и позволяет делать все навалом.