Выполнение результирующих строк для результата динамического собственного SQL-запроса

#sql #oracle #dynamic #native

#sql #Oracle #динамический #собственный

Вопрос:

Я схожу с ума по этому поводу. Я довольно новичок в динамическом SQL, поэтому, возможно, я просто не задаю Google правильный вопрос, но вот что я пытаюсь сделать… У меня есть запрос с динамическим SQL. Когда я запускаю этот запрос, он выдает несколько строк. Все эти строки (около 30) составляют один запрос объединения. Я могу скопировать все эти строки, вставить в новый запрос и запустить — работает нормально, но что мне нужно сделать, так это выполнить все это в одном запросе. Я просмотрел примеры использования execute immediate и fetch, но, похоже, я не могу заставить их фактически выдавать данные…в итоге они просто говорят что-то вроде «Выполнено успешно», но на самом деле не создают никаких результирующих строк. Результирующее имя столбца приведенного ниже SQL-кода — «qry_txt» — вместо того, чтобы выдавать его по номинальной стоимости, я хочу выполнить его как запрос. Опять же, я, возможно, плохо формулирую это, но я в основном пытаюсь превратить 2 запроса (с включенным шагом копирования / вставки вручную) в один запрос. Надеюсь, это имеет смысл…

Вот мой SQL:

 Select CASE when 
lead(ROWNUM) over(order by ROWNUM) is null then
'SELECT '||''''||T.TABLE_NAME||''''||' as TABLE_NAME,'||''''||T.COLUMN_NAME||''''||' as COLUMN_NAME, cast('|| T.COLUMN_NAME ||' as 
varchar2(100)) as SAMPLE_DATA ||
from rpt.'||T.TABLE_NAME ||' where '||T.COLUMN_NAME||' is not null and ROWNUM=1;'  
else
'SELECT '||''''||T.TABLE_NAME||''''||' as TABLE_NAME,'||''''||T.COLUMN_NAME||''''||' as COLUMN_NAME, cast('|| T.COLUMN_NAME ||' as 
varchar2(100)) as SAMPLE_DATA from rpt.'||T.TABLE_NAME ||' where '||T.COLUMN_NAME||' is not null and ROWNUM=1 union ' end as qry_txt
from all_tab_columns t where T.OWNER='rpt' and T.DATA_TYPE != 'BLOB' and T.DATA_TYPE != 'LONG' and T.TABLE_NAME = 'NME_DMN' 
ORDER BY ROWNUM asc;
  

Комментарии:

1. Ваша цель — открыть курсор, который возвращается вызывающему объекту, который затем извлекает строки (это проще и может быть сделано с помощью execute immediate ). Или вам нужен блок PL / SQL, который извлекает все строки (что сложнее и почти наверняка предполагает более сложный маршрут с использованием dbms_sql пакета)?

2. Из того, что я читал, открытие курсора звучит как правильный путь. Да, мне нужно извлечь все строки, как если бы я выполнял прямой запрос select. Пока я заканчиваю со строками, я открыт для любого метода, но самый простой был бы лучшим с точки зрения моей возможности повторить технику … 😉

3. Если вы хотите открыть курсор, который возвращается вызывающему, вызывающий не может быть блоком PL / SQL, который извлекает данные (ну, это может быть, если вы используете 12.1, и вы готовы стать еще более сложным). Вы могли бы вернуть курсор, скажем, SQL*Plus или в приложение C #, которое затем могло бы извлекать данные. Если вы хотите иметь блок PL / SQL, который извлекает все строки, вам понадобится более сложный dbms_sql путь. Я не уверен, какой из них действительно работает для вас.

4. Я бы сказал, если это не функция native sql в oracle (из коробки), то, вероятно, это не сработало бы для меня. Все примеры dbms_sql, с которыми я сталкивался, терпят неудачу для меня. Итак, возможно, открытие курсора не является ответом? Видите ли вы какой-либо другой готовый метод, который я могу использовать для достижения того, чего я хочу? Это моя первая попытка сделать что-то подобное, так что, возможно, это даже невозможно. Судя по результатам, которые я вижу в Google, я первый человек на планете, пытающийся это сделать, так что, возможно, это невыполнимо…

5. Это в высшей степени выполнимо. Используя execute immediate , вы можете с радостью вернуть курсор в приложение, которое знает, как опрашивать курсор, чтобы определить такие вещи, как количество и тип столбцов, чтобы извлечь данные. SQL*Plus знает, как это сделать, как это делает, реально, любой клиентский API (JDBC / ODBC / OLE DB / etc.). Если вы хотите написать блок PL / SQL, который извлекает данные, вам нужно написать более сложный dbms_sql код. Оба execute immediate и dbms_sql существуют «из коробки». Одно намного проще другого.

Ответ №1:

Вы не можете написать динамический запрос в SQL. Для этого необходимо использовать блок PLSQL. Пожалуйста, посмотрите, как вы можете это сделать. PS: код не тестируется.

 declare
  var1 <decalration same of column in select list> ;
  var2 <decalration same of column in select list> ;
  var3 <decalration same of column in select list> ;
  ....
  varn   ;

 begin
  for i in ( SELECT LEAD (ROWNUM) OVER (ORDER BY ROWNUM) COl1
              FROM all_tab_columns t
               WHERE     T.OWNER = 'rpt'
                     AND T.DATA_TYPE != 'BLOB'
                     AND T.DATA_TYPE != 'LONG'
                     AND T.TABLE_NAME = 'NME_DMN'
             ORDER BY ROWNUM ASC)

  Loop

     If i.col1 IS NULL Then

     execute immediate   'SELECT '
                           || ''''
                           || T.TABLE_NAME
                           || ''''
                           || ' as TABLE_NAME,'
                           || ''''
                           || T.COLUMN_NAME
                           || ''''
                           || ' as COLUMN_NAME, cast('
                           || T.COLUMN_NAME
                           || ' as 
                              varchar2(100)) as SAMPLE_DATA ||
                            from rpt.'
                           || T.TABLE_NAME
                           || ' where '
                           || T.COLUMN_NAME
                           || ' is not null and ROWNUM=1' into var1 , var2 ,var3 ....varn;

    Else

       execute immediate  'SELECT '
                           || ''''
                           || T.TABLE_NAME
                           || ''''
                           || ' as TABLE_NAME,'
                           || ''''
                           || T.COLUMN_NAME
                           || ''''
                           || ' as COLUMN_NAME, cast('
                           || T.COLUMN_NAME
                           || ' as 
            varchar2(100)) as SAMPLE_DATA from rpt.'
                           || T.TABLE_NAME
                           || ' where '
                           || T.COLUMN_NAME
                           || ' is not null and ROWNUM=1' into var1 , var2 ,var3 ....varn;

    end if;

  End Loop;             

  exception
   when others then
   dbms_output.put_lin(sqlcode ||'--'||sqlerrm);

End;  
  

Комментарии:

1. Я запустил это и получил эту ошибку: Ошибка поиска ORA-06550: строка 2, столбец 8: PLS-00103: обнаружен символ «<» при ожидании одного из следующих: постоянная таблица исключений длинная двойная ссылка символ время интервал временной метки дата двоичный национальный символ nchar

2. Я просто помогаю вам с телом. Это не фактический рабочий код. Я просто помог вам с тем, как вы можете работать дальше. Также мои комментарии встроены. Просто следуйте синтаксису и соответствующим образом измените свой код

3. Боюсь, я недостаточно знаю о вашей технике или ошибках, которые я получаю в настоящее время, чтобы заставить это работать на меня. Все еще пытаюсь…

4. Вы можете опубликовать код, который вы пытаетесь. Либо я, либо кто-то другой обязательно вам поможет. не забудьте пометить вопрос в разделе Oracle и опубликовать ошибку, с которой вы столкнулись

5. Я изменил ваш код, и теперь он выполняется, но он просто говорит «выполнено успешно», на самом деле он не возвращает строки. Код здесь: pastebin.com/XJLnb9Zi