Как вывести значения ROWTYPE в CSV незная имён всех столбцов?
Есть процедура, которая использует представление для вывода в CSV файл всех записей этого представления. Но любой пользователь может изменить это представление, так что структура столбцов может часто меняться.
Есть ли какой-нибудь способ выбрать все записи представления в коллекцию, и выводить элементы этой коллекции не указывая имна ВСЕХ столбцов?
Этot вопрос уже встаёт неоднократно, но не могу найти ответ на него, и должен изменять процедуру каждый раз, когда нужно выводить данные из изменённoго представление в CSV файл.
Фрагмент кода, который обычно использую для вывода, включает все имена столбцов:
PROCEDURE spoolToCSV is
cursor c1 is
select * from view1;
TYPE alldata_typ IS table of c1%rowtype;
v_dta alldata_typ;
BEGIN
v_file := UTL_FILE.FOPEN('CDMP_OUT_DIR', 'data.csv', 'W');
UTL_FILE.PUT_LINE(v_file, 'FSA_CODE,FSA_NAME,SERIES,VEHICLE_COUNT');
OPEN c1;
FETCH c1 BULK COLLECT INTO v_dta;
FOR i IN 1..v_dta.count LOOP
UTL_FILE.PUT_LINE(v_file,
v_dta(i).fsa_code ||', '||
v_dta(i).fsa_name ||', '||
v_dta(i).series ||', '||
v_dta(i).vehicle_count);
Свободный перевод вопроса Print values of TABLE OF RECORDS TYPE without knowing the COLUMN NAMES of record от участника @Swechchha
Ответы (2 шт):
Если используется UTL_FILE, то файл записывается на сервер БД. Если там нужен только CSV, то можно запускать команды SQL*Plus непосредственно из БД с помощью заданий планировщика.
Подробнее описал в блоге - хороним UTL_FILE.
Но если кратко, то планировщик может запустить сессию SQL*Plus, которая имеет встроенную поддержку CSV формата для выводимого результата.
Вероятно, для больших объемов данных, это будет намного быстрее, чем UTL_FILE.
Свободный перевод ответа от участника @Connor McDonald
Предложенное решение в ответе @Connor McDonald имеет один недостаток - выполняя непосредственно SQL*Plus команды, не удастся избавится от нежелательного вывода самого SQL*Plus, например, текста запроса или приглашения ввода.
Так как команды, которые могут подавить нежелательный вывод, доступны только при выполнении скрипта (@, @@, start), то необходимо выполнять цепочку команд в скрипте. Ниже рабочий пример, как надо сделать.
Создать примерно такой скрипт:
whenever oserror exit failure;
whenever sqlerror exit failure;
define objname=&1
conn me/pass@localhost/pdb1
set markup csv on
set feed off termout off verify off
spool /tmp/&objname..csv
select * from &objname;
spool off
Тестовое представление и запуск задания:
create or replace view view1 as
select level id, 'memo '||level memo, trunc (sysdate-3)+level dt
from dual connect by level<=3
/
declare
script varchar2 (32767) := '@ /<абс. путь к скрипту>/spoolcsv view1';
jobname varchar2 (30) := 'spoolCSV';
begin
dbms_scheduler.create_job (job_name=>jobname, job_type=>'SQL_SCRIPT',
job_action=>script, credential_name=>'oscred', enabled=>true, auto_drop=>true);
end;
/
Содержимое созданного файла:
$ cat /tmp/view1.csv
"ID","MEMO","DT"
1,"memo 1","20200821T000000"
2,"memo 2","20200822T000000"
3,"memo 3","20200823T000000"
PS Данное решение с небольшими изменениями будет также работать на локальной машине. Воспользуйтесь планировщиком заданий, доступным в ОС на локальной машине.