Oracle 11g - как объявить запись для хранения значений на основе динамического SQL - PullRequest
1 голос
/ 30 мая 2019

Резюме

Точно так же, как мой вопрос утверждает, мне любопытно узнать, как я могу определить запись, чтобы я мог хранить значения, полученные с помощью динамического SQL. У меня есть таблица, которая хранит SQL в столбцах CLOB. Целью END будет вызов функции PIPELINED с использованием query_id запроса, который должен быть запущен. На данный момент моя проблема не в том, как определить ТИП, чтобы я мог ТРУБОПРОВОДИТЬ данные. Я не могу определить функцию PIPELINED из-за того, что при объявлении функции PIPELINED ей требуется тип. В моем случае ТИП изменится в зависимости от желаемого запроса, содержащегося в таблице запросов.

Что я пробовал

Я прочитал об использовании DBMS_SQL и вижу, что есть особенность DBMS_SQL, которая DBMS_SQL.DEFINE_COLUMN, однако она требует, чтобы я явно определил столбцы - если я что-то здесь не упустил. Опять же ... я не знаю типы столбцов, возвращаемые из динамического sql ... они могут быть любыми и в любом порядке.

Пример моей проблемы

Приведенный ниже код является простейшим примером моей проблемы. ЗАПИСЬ, которую я хочу заполнить в приведенном ниже примере кода: rec_cursor_query. Во всех других не динамических SQL это будет определяться на основе таблицы или явно определены с использованием имен столбцов и ключевого слова% TYPE. Can't use this: rec_cursor_query employees%ROWTYPE;.

DECLARE

  /* Cursor Pointer */
  cur_Query   SYS_REFCURSOR;

  /* Store Dynamic SQL */
  q           VARCHAR2(2000);

  /* Declare Record based on Dynamic SQL */
  --rec_cursor_query  ????table%ROWTYPE;  /* I realize I can't do this... but what can I do? */

BEGIN

  /* Fake Query Below saved into q */
  q   :=    q'~SELECT 1001 AS pkey, 'Jake' AS firstname, 'Johnson' AS lastname FROM dual~';

  /* Output Query just to show query was saved */
  dbms_output.put_line(q);

  OPEN cur_Query FOR
    q;

  LOOP

    FETCH cur_Query INTO rec_cursor_query; /* Again here... I can't do this due to it not being Defined */

    EXIT WHEN cur_Query%NOTFOUND;

  END LOOP;

  CLOSE cur_Query;


END
;

1 Ответ

1 голос
/ 31 мая 2019

Проще говоря, это невозможно в Oracle SQL. SQL строго типизирован. Ничего из этого "если это выглядит как утка" чепуха для нас! Функция table() работает только с предопределенным типом (обычно это объект SQL), поскольку ей необходимо знать проекцию. Если вам интересно, мы не можем использовать ANYDATASET или ANYTYPE в качестве возвращаемого значения для конвейерных функций (PLS-00630: конвейерные функции должны иметь поддерживаемый тип возврата коллекции).

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

Другой вариант - понять, что SQL - это не тот инструмент для работы. Есть другие языки, которые изначально поддерживают рефлексию и такие возможности, основанные на метаданных. Используйте слабые ссылки для передачи данных в клиентские приложения. Ссылочные курсоры сопоставляются с наборами результатов ODBC и JDBC, которые могут интерпретировать проекцию на лету. Или обновите до Oracle 12c, который представил поддержку неявных наборов результатов в DBMS_SQL. Узнать больше .

...