Лучший способ получить динамический набор результатов в курсор - PullRequest
2 голосов
/ 29 октября 2019

У меня есть функция отчетности, которая принимает запрос SQL и генерирует для него некоторые агрегаты и преобразования. Все запросы возвращают столбцы со структурой: ID, COL1, COl2, COL3 .... COL25.

Эта функция извлекает результаты в курсор для их обработки, сохраняя строку в переменной следующим образом:

следующим образом:

    OPEN C1 FOR V_SQL;
        LOOP
            CASE COLUMN_COUNT
                WHEN 3 THEN
                    FETCH C1 INTO ROW.C1,ROW.C2,ROW.C3;
                WHEN 4 THEN
                    FETCH C1 INTO ROW.C1,ROW.C2,ROW.C3,ROW.C4;
                WHEN 5 THEN
                    FETCH C1 INTO ROW.C1,ROW.C2,ROW.C3,ROW.C4,ROW.C5;
                ... (until 29 columns)

Теперь требуется поддержка до 100 столбцов. Это сделало бы код очень большим. Как я могу сделать это динамически, как массив?

1 Ответ

0 голосов
/ 01 ноября 2019

Эта процедура получает текст SQL-запроса (из безопасного источника - обратите внимание, что в противном случае вам следует реализовать некоторые базовые проверки на наличие вредоносного кода) вместе с количеством столбцов, которые вы хотите получить.

Процедура анализирует запрос, динамически определяет столбцы в необходимом количестве и выбирает строки для создания DBMS_OUTPUT - вы должны получить идею для своего варианта использования.

Вы можете опустить col_cnt параметр и получить значение от курсора, используя DBMS_SQL.DESCRIBE_COLUMNS, но это потребует дополнительного открытия / закрытия курсора.

CREATE OR REPLACE PROCEDURE ftch ( 
     sql_txt      IN VARCHAR2, 
     col_cnt      IN NUMBER) IS 

     type array_vc_t is varray(100) of varchar2(30);     
     id                 NUMBER; 
     cols               array_vc_t := array_vc_t(); 
     source_cursor      INTEGER;  
     ignore             INTEGER; 
  BEGIN 

     source_cursor := dbms_sql.open_cursor; 
     DBMS_SQL.PARSE(source_cursor,sql_txt, DBMS_SQL.NATIVE); 

     DBMS_SQL.DEFINE_COLUMN(source_cursor, 1, id); 
     for i in 1..col_cnt loop
          cols.extend();     
          DBMS_SQL.DEFINE_COLUMN(source_cursor, i+1, cols(i), 30); 
     end loop; 
     ignore := DBMS_SQL.EXECUTE(source_cursor); 

     LOOP 
       IF DBMS_SQL.FETCH_ROWS(source_cursor)>0 THEN 

         DBMS_SQL.COLUMN_VALUE(source_cursor, 1, id); 
         for i in 1..col_cnt loop
             DBMS_SQL.COLUMN_VALUE(source_cursor, i+1, cols(i)); 
         end loop;
         dbms_output.put_line('id= '|| id );
         for i in 1..col_cnt loop
             dbms_output.put_line('        i='|| i || ' col = '|| cols(i)  );
         end loop;         
      ELSE 

  -- No more rows - exit
        EXIT; 
      END IF; 
    END LOOP; 

     DBMS_SQL.CLOSE_CURSOR(source_cursor); 
   EXCEPTION 
     WHEN OTHERS THEN 
       IF DBMS_SQL.IS_OPEN(source_cursor) THEN 
         DBMS_SQL.CLOSE_CURSOR(source_cursor); 
       END IF; 
       RAISE; 
  END; 
/

пример

exec ftch('select id, col1, col2 from tab',2);

вывод

id= 1
        i=1 col = xx1
        i=2 col = xx2
id= 2
        i=1 col = yy1
        i=2 col = yy2
id= 3
        i=1 col = zz1
        i=2 col = zz2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...