@Andrey1_M

Как вывести всю строку в FOR..IN не перечисляя вручную столбцы?

Как вывести всю строку в FOR..IN в DBMS_OUTPUT? + заголовок (заголовок - решено)

begin
   FOR colind IN (select 1 as t from dual)
   LOOP

      DBMS_OUTPUT.PUT_LINE(colind.t); --тут столбец надо указывать, а мне нужно сразу всю строку

   END LOOP;
end;


моя попытка решить проблему
declare
   cur1 PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;
   cols DBMS_SQL.DESC_TAB;
   ncols PLS_INTEGER;
   l_html varchar2(1000);
    l_output    VARCHAR2(100):= 'ok ';
begin

    -- Разбор запроса
   DBMS_SQL.PARSE (cur1, 'select 1 field_11, ''river'' field_22 from dual 
                          union all
                          select 1 field_11, ''sharf'' field_22 from dual', DBMS_SQL.NATIVE);
   -- Получение информации о столбцах
   DBMS_SQL.DESCRIBE_COLUMNS (cur1, ncols, cols);
   -- Вывод каждого из имен столбцов
   FOR colind IN 1 .. ncols
   LOOP
      --DBMS_OUTPUT.PUT_LINE (cols (colind).col_name);
      l_html:=l_html||''||cols (colind).col_name||' ';
   END LOOP;
   DBMS_OUTPUT.PUT_LINE(l_html);  
   
   FOR cur IN (select 1 field_11, 'river' field_22 from dual 
               union all
               select 1 field_11, 'sharf' field_22 from dual)
   LOOP
          --явное указание работает
           DBMS_OUTPUT.PUT_LINE(cur.field_22||' ');
           
          --попытка динамического задания имени столбца, не работает
          -- EXECUTE IMMEDIATE 'BEGIN :a := :a || ''OK''; DBMS_OUTPUT.PUT_LINE(cur.'||cols (cur1).col_name||'); END;' USING IN OUT l_output; 
       
          /* --перечислить заново в цикле столбцы чтобы по каждому вытащить данные? ne rabotaet
          FOR colind1 IN 1 .. ncols
           LOOP
              --попытка динамического задания имени столбца, тут видимо надо новый курсор открывать? не работает 
              --EXECUTE IMMEDIATE 'BEGIN :a := :a || ''OK''; DBMS_OUTPUT.PUT_LINE(cur.'||cols (cur1).col_name||'||'); END;' USING IN OUT l_output;  
              
              DBMS_OUTPUT.PUT_LINE(cur.field_22||' ');
           END LOOP;  */
   END LOOP; 
   DBMS_SQL.CLOSE_CURSOR (cur1);
end;

Вывод:

FIELD_11 FIELD_22 
river 
sharf

С явным указанием выводит, не могу понять как сделать EXECUTE IMMEDIATE для куска pl/sql кода, чтобы подставить имя столбца или ещё где-то ошибся скорее всего.
  • Вопрос задан
  • 133 просмотра
Пригласить эксперта
Ответы на вопрос 1
erge
@erge
Примус починяю
DECLARE
    l_sql        VARCHAR2(32767):='
      SELECT 1 field_11, ''river'' field_22 FROM DUAL
      UNION ALL
      SELECT 1 field_11, ''sharf'' field_22 FROM DUAL
    ';
    l_cur        PLS_INTEGER := DBMS_SQL.OPEN_CURSOR;
    l_ind        PLS_INTEGER;
    l_col_count  PLS_INTEGER;
    l_col_names  DBMS_SQL.DESC_TAB;
    l_out        VARCHAR2(32767);
    col_val_chr  VARCHAR2(32767);
    LNBR         VARCHAR2(2)  := CHR(13)||CHR(10);
    col_delim    VARCHAR2(20) := '</td><td>';
    row_delim    VARCHAR2(20) := '</td></tr>'|| LNBR ||'<tr><td>';
BEGIN
    -- Разбор запроса
    DBMS_SQL.PARSE (
      l_cur,
      l_sql,
      DBMS_SQL.NATIVE
    );
    -- Получение информации о столбцах
    DBMS_SQL.DESCRIBE_COLUMNS (l_cur, l_col_count, l_col_names);
    -- Вывод каждого из имен столбцов
    FOR col_ind IN 1 .. l_col_count
    LOOP
        -- Определим тип столбца
        DBMS_SQL.DEFINE_COLUMN(l_cur, col_ind, col_val_chr, 32767);
        -- Выводим наимнование столбца
        l_out := l_out || l_col_names(col_ind).col_name;
        -- Если не последний эл. вставляем разделитель
        IF col_ind != l_col_count
        THEN
            l_out := l_out || col_delim;
        END IF;
    END LOOP;

    -- Выполняем и фетчим курсор
    l_ind := DBMS_SQL.EXECUTE (l_cur);
    LOOP
        l_ind := DBMS_SQL.FETCH_ROWS( l_cur );
        EXIT WHEN l_ind = 0;

        l_out := l_out || row_delim;

        FOR col_ind IN 1 .. l_col_count
        LOOP
            -- Читаем и выводим значение
            DBMS_SQL.COLUMN_VALUE (l_cur, col_ind, col_val_chr);
            l_out := l_out || col_val_chr;
            -- Если не последний эл. вставляем разделитель
            IF col_ind != l_col_count
            THEN
                l_out := l_out || col_delim;
            END IF;
        END LOOP;
    END LOOP;
    DBMS_SQL.CLOSE_CURSOR (l_cur);
    DBMS_OUTPUT.PUT_LINE('<table>'||LNBR||'<tr><td>'|| l_out ||'</td></tr>'||LNBR||'</table>');
END;
/

/*
    -- Если задать разделители полей ; и LNBR то на выходе получим CSV данные
    col_delim    VARCHAR2(20) := ';';
    row_delim    VARCHAR2(20) := LNBR;
*/


см. пример на dbfiddle

PS: Вы видимо что-то недочитали :)
Спасибо, сам разобрался, даже и не знал что так можно, теперь наверно буду использовать :)

UPDATE:
Можно обернуть в функцию и помимо прочего передавать в нее тип разделителя (для HTML можно передавать стили или classname для таблицы) и на выходе иметь разный формат данных.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы