Преобразование результирующего набора из одной строки в ассоциативный массив - PullRequest
2 голосов
/ 24 апреля 2011

Скажите, у меня есть следующий запрос:

select 1 foo, 2 bar, 3 baz from dual;

По сути, этот запрос всегда возвращает мне одну строку. Мне нужно создать ассоциативный массив из этого, такого типа:

arr('foo') = 1;
arr('bar') = 2;
arr('baz') = 3;

Я знаю, что набор результатов - это только одна строка. Я не знаю ни количества столбцов, ни имен столбцов.

Есть идеи?

Спасибо.

UPD:

Мой друг нашел красивое и элегантное решение с использованием XML:

  SELECT
   XMLTYPE(EXTRACT(VALUE(T), '/*') .GETSTRINGVAL()) .GETROOTELEMENT() NODE,
   EXTRACTVALUE(COLUMN_VALUE, '/*') NODEVALUE
    FROM
   TABLE(XMLSEQUENCE(XMLTYPE((CURSOR
   (
      --this is the query that needs to be transformed
      SELECT
       *
        FROM
       some_table
       WHERE some_table.id = 123

   )
   )) .EXTRACT('/ROWSET/ROW/*'))) T;

Ответы [ 2 ]

2 голосов
/ 24 апреля 2011

Вот простой пакет, который заполняет ассоциативный массив из таблицы пар ключ-значение.Это простой случай.

create or replace package dynaa as
    procedure pop;
    procedure print;
end;
/

create or replace package body dynaa as

    type aa is table of number
        index by varchar2(30);
    this_aa aa;

    procedure pop
    is
    begin
        for r in ( select * from t42 )
        loop
            this_aa (r.id) := r.col1;
        end loop;
    end pop    ;

    procedure print
    is
        idx varchar2(30);
    begin
        idx := this_aa.first();
        while idx is not null
        loop
            dbms_output.put_line(idx ||'='||this_aa(idx));
            idx := this_aa.next(idx);
        end loop;
    end print;
end;
/

И он работает довольно аккуратно ....

SQL> set serveroutput on
SQL>
SQL> exec dynaa.pop

PL/SQL procedure successfully completed.

SQL> exec dynaa.print
DAISY HEAD MAISIE=6969
FOX IN SOCKS=4242
MR KNOX=2323

PL/SQL procedure successfully completed.

SQL>

Но то, что вы хотите, является более сложным: динамически заполнять массив, не зная проекциизапроса.Следующее является ужасно упрощенной реализацией, которая будет работать, если рассматриваемая таблица содержит одну строку.Его можно легко расширить для обработки таблицы с несколькими строками.

Мы перегружаем процедуру POP() следующим образом:

procedure pop
    ( tabname user_tab_columns.table_name%type );

procedure pop
    ( tabname user_tab_columns.table_name%type );
is
    n number;
begin
    for r in ( select column_name 
               from user_tab_columns
               where table_name = tabname)
    loop
        execute immediate 'select '||r.column_name||' from '||tabname into n;
        this_aa (r.column_name) := n;
    end loop;
end pop    ;

Итак, это тоже работает:

SQL> exec dynaa.pop('T23')

PL/SQL procedure successfully completed.

SQL>
SQL> exec dynaa.print
COL1=2323
COL2=4242
COL3=6969

PL/SQL procedure successfully completed.

SQL>

Меня не слишком беспокоит производительность, вызванная инициализацией массива таким мрачным образом.Учитывая, что запись остается в кеше, это не так уж плохо.И если вы звоните POP() так часто, что производительность действительно становится проблемой, то вам, вероятно, не стоит использовать ассоциативный массив в первую очередь: или регулярный поиск, или кэширование набора результатов будет лучшим вариантом.

1 голос
/ 24 апреля 2011

Очень краткий ответ - взглянуть на динамический SQL старого стиля (до Oracle 9), используя пакет DBMS_SQL. Вы можете использовать DESCRIBE_COLUMNS для получения количества (и типов данных) столбцов и COLUMN_VALUE для каждой записи в таблице PL / SQL, возвращаемой DESCRIBE_COLUMNS, для выборки каждого значения столбца в отдельности.

После этого довольно просто превратить строку в ассоциативный массив.

...