Получение результатов в наборе результатов из динамического SQL в Oracle - PullRequest
3 голосов
/ 05 апреля 2010

Этот вопрос похож на пару других, которые я нашел в StackOverflow, но различия достаточно существенны для меня, чтобы оправдать новый вопрос, поэтому вот он:

Я хочу получить набор результатов из динамического SQL в Oracle, а затем отобразить его как набор результатов в инструменте, подобном SqlDeveloper, так же, как если бы я выполнял оператор динамического SQL напрямую. Это просто в SQL Server, поэтому, если быть точным, вот пример из SQL Server, который возвращает набор результатов в SQL Server Management Studio или Query Explorer:

EXEC sp_executesql N'select * from countries'

Или точнее:

DECLARE @stmt nvarchar(100)
SET @stmt = N'select * from countries'
EXEC sp_executesql @stmt

Вопрос «Как вернуть набор результатов / курсор из анонимного блока Oracle PL / SQL, который выполняет динамический SQL?» решает первую половину проблемы - выполнение динамического SQL в курсоре. На вопрос «Как заставить процедуру Oracle возвращать наборы результатов» дается аналогичный ответ. Поиск в Интернете выявил множество вариаций одной и той же темы, причем все они касались только первой половины моего вопроса. Я нашел в этом посте , объясняющем, как это сделать в SqlDeveloper, но в нем используется немного функциональности SqlDeveloper. Я на самом деле использую пользовательский инструмент запросов, поэтому мне нужно, чтобы решение было автономным в коде SQL. Этот пользовательский инструмент запросов аналогично не имеет возможности отображать выходные данные операторов print (dbms_output.put_line); он отображает только наборы результатов. Вот еще еще один возможный путь , использующий «execute немедленный ... массовый сбор», но этот пример снова отображает результаты с циклом операторов dbms_output.put_line. Эта ссылка пытается обратиться к теме, но на этот вопрос так и не был получен ответ.

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


Итак, подведем итог:

  • Я хочу выполнить произвольный оператор SQL (следовательно, динамический SQL).
  • Платформа - Oracle.
  • Решение должно быть блоком PL / SQL без процедур или функций.
  • Выходные данные должны быть сформированы как канонический набор результатов; нет печатных заявлений.
  • Выходные данные должны отображаться как набор результатов в SqlDeveloper без использования каких-либо специальных функций SqlDeveloper.

Есть предложения?

Ответы [ 4 ]

0 голосов
/ 04 июля 2019

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

DEFINE view_name = 'my_results_view';
SET FEEDBACK OFF
SET ECHO OFF
DECLARE
  l_view_name VARCHAR2(40)     := '&view_name';
  l_query     VARCHAR2(4000)   := 'SELECT 1+level as id,
                                  ''TEXT''||level as text  FROM DUAL ';
  l_where_clause VARCHAR2(4000):= 
                           ' WHERE TRUNC(1.0) =  1 CONNECT BY LEVEL < 10';
BEGIN
     EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW '
                       || l_view_name
                       || ' AS '
                       || l_query
                       || l_where_clause;
END;
/
 select * from &view_name;

enter image description here

0 голосов
/ 05 апреля 2010

В TOAD при выполнении приведенного ниже скрипта вам будет предложено указать тип v_result. Из списка выбора типов выберите курсор, затем результаты отобразятся в сетке данных Toad (таблица Excel похожа на результат). Тем не менее, при работе с курсорами в качестве результата вы всегда должны писать две программы (клиент и сервер). В этом случае «TOAD» будет клиентом.

DECLARE
   v_result      sys_refcursor;
   v_dynamic_sql   VARCHAR2 (4000);
BEGIN
   v_dynamic_sql := 'SELECT * FROM user_objects where ' || ' 1 = 1';

   OPEN :v_result FOR (v_dynamic_sql);
END;

В Oracle Developer SQL может существовать аналогичный механизм для запроса привязки.

0 голосов
/ 07 апреля 2010

Вы, похоже, просите кусок кода PL / SQL, который будет принимать произвольный запрос, возвращающий набор результатов с неопределенной структурой, и 'forward / restructure', который каким-то образом набор результатов будет таким, который может быть легко воспроизведен некоторыми " пользовательский инструмент GUI ".

Если это так, посмотрите на DBMS_SQL для динамического SQL. Он имеет процедуру DESCRIBE_COLUMNS, которая возвращает столбцы из динамического оператора SELECT. Шаги, которые вам понадобятся:

  1. Разбор заявления
  2. Опишите набор результатов (имена столбцов и типы данных)
  3. Извлекает каждую строку и для каждого столбца вызывает зависимую от типа данных функцию, чтобы вернуть это значение в локальную переменную
  4. Поместите эти локальные переменные в определенную структуру для возврата в вызывающую среду (например, непротиворечивые имена столбцов [такие как col_1, col_2], вероятно, все из VARCHAR2)

В качестве альтернативы вы можете попробовать встроить запрос в оператор XMLFOREST и проанализировать результаты из XML.


Добавлено: В отличие от SQL Server, вызов Oracle PL / SQL не будет «естественно» возвращать один набор результатов. Он может открыть один или несколько курсоров ref и передать их обратно клиенту. Затем клиент несет ответственность за выборку записей и столбцов из этих ссылок. Если ваш клиент не / не может справиться с этим, то вы не можете использовать вызов PL / SQL. Хранимая функция может возвращать предварительно определенный тип коллекции, что позволяет вам делать что-то вроде «select * from table (func_name ('select * from country')))». Однако функция не может выполнять DML (обновление / удаление / вставка / слияние), потому что она уничтожает любые концепции согласованности для этого запроса. Плюс возвращаемая структура фиксируется так, что

select * from table(func_name('select * from countries'))

должен возвращать тот же набор столбцов (имена столбцов и типы данных), что и

select * from table(func_name('select * from persons'))

Возможно, используя DBMS_SQL или XMLFOREST, для такой функции взять динамический запрос и реструктурировать его в предварительно определенный набор столбцов (col_1, col_2 и т. Д.), Чтобы его можно было возвращать согласованным образом. Но я не понимаю, какой в ​​этом смысл.

0 голосов
/ 05 апреля 2010

Попробуйте попробовать это.

DECLARE
  TYPE EmpCurTyp  IS REF CURSOR;
  v_emp_cursor    EmpCurTyp;
  emp_record      employees%ROWTYPE;
  v_stmt_str      VARCHAR2(200);
  v_e_job         employees.job%TYPE;
BEGIN
  -- Dynamic SQL statement with placeholder:
  v_stmt_str := 'SELECT * FROM employees WHERE job_id = :j';

  -- Open cursor & specify bind argument in USING clause:
  OPEN v_emp_cursor FOR v_stmt_str USING 'MANAGER';

  -- Fetch rows from result set one at a time:
  LOOP
    FETCH v_emp_cursor INTO emp_record;
    EXIT WHEN v_emp_cursor%NOTFOUND;
  END LOOP;

  -- Close cursor:
  CLOSE v_emp_cursor;
END;


declare
  v_rc    sys_refcursor;
begin
   v_rc := get_dept_emps(10);  -- This returns an open cursor
   dbms_output.put_line('Rows: '||v_rc%ROWCOUNT);
   close v_rc;
end;

Найдите больше примеров здесь. http://forums.oracle.com/forums/thread.jspa?threadID=886365&tstart=0

...