PLSQL: как создать курсор, используя переменную в качестве table_name

Я пытаюсь сделать следующее в PLSQL:

  • У меня есть таблица, которая содержит список имен таблиц, например: Table_1, Table_2, Table_3 и т. д.

  • Я переписываю эту таблицу ежедневно, поэтому список таблиц является динамическим, сегодня вы можете получить 3 таблицы, завтра 7 таблиц и так далее.

  • Основываясь на этом списке таблиц, я хочу экспортировать содержимое этих таблиц, используя UTL_FILE.

До сих пор я пытался получить имена таблиц в переменную, а затем перебрать переменную, но это не сработало.

У меня есть следующие коды:

Declare
    var1 SYS_REFCURSOR;
    var2 varchar2(20);
    var3 varchar2(20);    
    ARCHIVE UTL_FILE.FILE_TYPE;
    Cursor cur2 IS SELECT TABLE_NAME FROM LIST_OF_TABLES; 

BEGIN   

ARCHIVO:=UTL_FILE.FOPEN('test_path','test.txt','W');

        for i in cur2 loop

        var2:= i.table_name;

        OPEN var1 for 'SELECT SKUID, CMRPRICE FROM '||VAR2;
        loop

       FOR C IN MICURSOR LOOP
  UTL_FILE.PUT_LINE(ARCHIVE,(''||C.SKUID||''||','||''||  C.CMRPRICE||''));
      END LOOP;
      UTL_FILE.FCLOSE(ARCHIVE);
        close var1;
        end loop;

END;

я ожидаю получить такое же количество файлов, как таблицы в списке таблиц

заранее спасибо


person Juan Baquero    schedule 02.08.2019    source источник
comment
Можете ли вы уточнить, что для вас означает «не работает»? Вы получаете сообщение об ошибке? Код не делает то, что вы ожидаете? Как минимум, вы открываете только один файл, и это вне цикла. Если вы хотите, чтобы каждая таблица записывалась в отдельный файл, вам нужно открывать и закрывать файл внутри цикла. И, предположительно, используйте имя файла, связанное с именем таблицы.   -  person Justin Cave    schedule 03.08.2019
comment
Вы использовали два столбца -- SKUID, CMRPRICE. Итак, существуют ли эти столбцы в каждой таблице?   -  person Popeye    schedule 03.08.2019
comment
Кстати, вы можете попробовать поставить when others then dbms_output.put_line( dbms_utility.format_error_stack ); dbms_output.put_line( dbms_utility.format_error_backtrace ); непосредственно перед END;, указанным внизу.   -  person Barbaros Özhan    schedule 03.08.2019
comment
Что такое MICURSOR? Вы открываете и закрываете динамический курсор var1, но не извлекаете из него данные.   -  person William Robertson    schedule 03.08.2019


Ответы (1)


я ожидаю получить такое же количество файлов, как таблицы в списке таблиц

В этом случае вам нужно открыть отдельный файл для каждой таблицы.

Кроме того, вы должны быть согласованы с именами переменных (archivo|archive, cur2|micursor). Обычно лучше давать переменным осмысленные имена, отражающие их использование. Слишком легко спутать var1 и var2.

Я думаю, вы хотите, чтобы содержимое файлов было заключено в кавычки. Я использовал двойные кавычки, что является стандартом для формата CSV.

Этот код определяет тип записи PL/SQL, tgt_rec, с проекцией, которая соответствует проекции строки запроса. Мы открываем курсор динамической ссылки, затем в цикле извлекаем записи в эту переменную записи, пока курсор не будет исчерпан.

declare
    file_handle utl_file.file_type;

    rc sys_refcursor;          
    cursor cur_tables is 
        select table_name from list_of_tables; 
    type tgt_rec is record ( skuid number, cmrprice number); 
    l_rec tgt_rec;

begin   

    << tables >>
    for i in cur_tables loop

        file_handle := utl_file.fopen('test_path', i.table_name||'.csv','w');

        open rc for 'select skuid, cmrprice from '||i.table_name;

        << table_rows >>
        loop

           fetch rc into l_rec;
           exit when rc%not found;

            utl_file.put_line(file_handle, '"'||l_rec.skuid||'","'||  l_rec.cmrprice||'"');

        end loop table_rows;        

        utl_file.fclose(file_handle);

        close rc;

    end loop tables;

end;
/

Вам могут не понравиться косметические изменения, которые я внес в вашу программу (например, .csv для расширений файлов), и, очевидно, вы можете отменить их. В конце концов, вы — Джозайя Споуд своего исполняемого кода.


«Вы не знаете, могу ли я распечатать результат двух сценариев, используя одну и ту же структуру кода?»

Это зависит. Вы можете преобразовать этот анонимный блок в процедуру и передать строку запроса — 'select skuid, cmrprice from ' — в качестве параметра. Это позволит вам варьировать выполняемый запрос. Однако вам все равно нужно извлечь набор результатов во что-то, и это что-то должно соответствовать структуре проекции: такое же количество столбцов и тот же тип данных. Так что это ограничивает вашу гибкость.

К счастью, PL/SQL — правильный язык программирования с множеством возможностей (хотя и не в стиле Java Reflection). Таким образом, у вас есть возможность написать какой-нибудь серьезно модульный набор программ с подпрограммами для общих вещей, таких как обработка файлов, и подпрограммами для обработки данных, специфичных для запроса.

person APC    schedule 03.08.2019
comment
Является ли Josiah Spode of x британским выражением? Этот точно не пересек пруд :-) - person Justin Cave; 04.08.2019
comment
@JustinCave - на самом деле вы - New York Times чего-то, что рифмуется с Шеф-повар Джон. - person APC; 04.08.2019
comment
@APC спасибо за ответ, однако у меня проблема с выполнением сценария: ORA-06550: LINE 19, столбец 21: PLS-00221: «RC» не является процедурой или не определена. Строка 19: for recs in rc loop - person Juan Baquero; 05.08.2019
comment
@APC Большое спасибо! С Уважением - person Juan Baquero; 05.08.2019
comment
@APC Знаете ли вы, могу ли я распечатать результат двух сценариев, используя одну и ту же структуру кода? (Я не хочу повторять это копировать (вставить) - person Juan Baquero; 05.08.2019