Xpoint
   [напомнить пароль]

Выборка поля из записи определяемого только на этапе исполнения (Oracle/PLSQL)

Метки: [без меток]
2008-05-27 17:44:25 [обр] Thirteensmay(3/157)[досье]

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

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

Запись Результат%ROWTYPE;

FETCH Результат INTO Запись;
x1 := Запись.ИмяПоля;

Получается что ИмяПоля или Запись я должен определить заранее, что по изложенным выше причинам невозможно. Как быть ?
В принципе задача решается иными методами, но это достаточно геморойно, возможно ли как то выбирать значение поля имя котрого определяется в динамике ?

спустя 29 минут [обр] GRAy(0/259)[досье]
Да уж ;) PL\SQL это вам не javascript ;)))
Вообще-то есть такая вещь как DBMS_SQL, может вы про неё и знаете. Но я, обычно, когда сталкивался с подобной задачей - искал способ изменить условия так, чтобы это не требовалось. Как правило находил ;)))
спустя 16 часов [обр] Thirteensmay(3/157)[досье]
К сожалению динамический SQL не поможет, у меня на входе уже открытый курсор. Надо подбить суммы столбцов и на выход вернуть такойже точно курсор но со строкой итогов в конце. Ладно чтож, спасибо и на том, наверное щас буду извращаться с особого формата промежуточным хранилищем.
спустя 7 часов [обр] Thirteensmay(3/157)[досье]
Ха ! Задача таки имеет решение впрямую, оказывается нативный динамический SQL может создавать и динамический PL/SQL.
спустя 25 минут [обр] GRAy(0/259)[досье]
Thirteensmay[досье] А курсор вы из него вернуть сможете? Если сможете - поделитесь ;)
спустя 16 часов [обр] Thirteensmay(3/157)[досье]

Получилось. Есть конечно некоторые ограничения, но мелочные. Динамически формируемый PL/SQL должен быть полноценным завершенным блоком, т.е. начинаться с DECLARE или BEGIN и оканчиваться END; Он размещается в глобальной области видимости пакета и имеет доступ только к глобальным определениям (процедурам, переменным и т.п.). Если вызывается из процедуры то это эквивалентно вызову из этой процедуры другой процедуры, т.е. переменные не видны.

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

result_set sys_refcursor;
result_set2 sys_refcursor;
...
open result_set for ...

delete from tv_report_result;
        
execute immediate
'declare'
|| ' procedure myproc(rset sys_refcursor, rset2 out sys_refcursor) is'
|| ' x1 varchar2(4000);'
|| ' x2 varchar2(4000);'
|| ' x3 varchar2(4000);'
|| ' x4 varchar2(4000);'
|| ' x5 varchar2(4000);'
|| ' x6 varchar2(4000);'
|| ' begin'
|| '   fetch rset into x1, x2, x3, x4, x5, x6;'
|| '   insert into tv_report_result (rec_no, field_id, field_value) values(1, 1, x1);'
|| '   open rset2 for select * from tv_report_result;'
|| ' end;'
|| ' begin'
|| '   myproc(:p1, :p2);'
|| ' end;'
using result_set, out result_set2;
        
result_set := result_set2;

result_set - курсор произвольной структуры, она известна только во время исполнения (после open result_set for ...)
Далее динамически формируется процедура myproc, в нее с помощью using передаются и возвращаются курсоры. Использовать rset%rowtype в динамике не получилось, но это легко обходится т.к. на этапе исполнения структура известна то можно динамически определить x1, x2 ... сколько нужно и сформировать соответствующую строку fetch.

В начале выполнения этого примера result_set имеет 6 полей, в конце - 3 (по таблице tv_report_result, через result_set2).

Мля, аж интересно, они в оракле хоть ченить не реализовали ?

Powered by POEM™ Engine Copyright © 2002-2005