Как спулировать несколько файлов в цикле? - PullRequest
1 голос
/ 08 апреля 2019

Я использую Oracle 12c.

У меня есть таблица СОТРУДНИКОВ, которая выглядит примерно так:

EMPLOYEE_NAME | DEPARTMENT_NAME
--------------|----------------
Jim           | Sales
Barb          | Marketing
Paul          | Sales
Frank         | Sales
Cindy         | Accounting
Carl          | Marketing
... and so on ...

Я бы хотел сделать что-то подобное, если PL / SQL разрешил это:

FOREACH dept IN (SELECT DISTINCT DEPARTMENT_NAME FROM EMPOLYEES) DO
    SPOOL 'list_' || :dept || '.txt';
    SELECT EMPLOYEE_NAME
    FROM EMPLOYEES
    WHERE DEPARTMENT_NAME = :dept;
    SPOOL OFF;
DONE;

, что приведет к набору таких файлов:

list_Sales.txt:

Jim
Paul
Frank

list_Marketing.txt

Barb
Carl

list_Accounting.txt

Cindy

... и так далее ...

Есть идеи, как мне этого добиться?

Спасибо.

Ответы [ 2 ]

3 голосов
/ 08 апреля 2019

spool - команда клиента, она не имеет никакого значения в блоке PL / SQL; и вы не можете писать в файлы на клиентском компьютере из PL / SQL. Вы можете написать на сервер , используя utl_file (как предложено @kfinity и продемонстрировано @ BarbarosÖzhan), но это может не подходить для вашей ситуации.

Если вы хотите придерживаться буферизации на клиентском компьютере и не хотите постобрабатывать вывод в несколько файлов (как предложено @KaushikNayak), вы можете использовать другой уровень буферизации для генерации скрипта, что-то вроде :

spool temp_script.sql

select distinct 'spool list_' || department_name || '.txt' || chr(10)
  || 'select employee_name from employees where department_name = '''
    || department_name || ''' order by employee_name;' || chr(10)
from employees;

spool off

@temp_script.sql

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

set pages 0
set lines 500
set trimspool on
set feedback off
set echo off

spool temp_script.sql

prompt set pages 0
prompt set lines 500
prompt set trimspool on
prompt set feedback off
prompt set echo off

select distinct 'spool list_' || department_name || '.txt' || chr(10)
  || 'select employee_name from employees where department_name = '''
    || department_name || ''' order by employee_name;' || chr(10)
from employees;

prompt spool off

spool off

@temp_script.sql

Содержимое temp_script.sql в этом случае заканчивается примерно так:

set pages 0
set lines 500
set trimspool on
set feedback off
set echo off
spool list_Administration.txt
select first_name || ' ' || last_name from employees where department_id = 10 order by last_name, first_name;
spool list_Marketing.txt
select first_name || ' ' || last_name from employees where department_id = 20 order by last_name, first_name;
spool list_Purchasing.txt
select first_name || ' ' || last_name from employees where department_id = 30 order by last_name, first_name;
...
spool list_Payroll.txt
select first_name || ' ' || last_name from employees where department_id = 270 order by last_name, first_name;
spool off

и один файл для каждого отдела, например list_Accounting.txt

William Gietz
Shelley Higgins

и list_Executive.txt:

Lex De Haan
Steven King
Neena Kochhar

и т.д.. В этом примере есть несколько пустых файлов, но если бы я сделал начальный запрос, соединяющий две таблицы, то его бы не было; так как вы запрашиваете одну таблицу, которая для вас тоже не произойдет.

1 голос
/ 08 апреля 2019

Вы можете использовать пакет utl_file для создания файла потока операционной системы, как указано @kfinity

1) Создайте каталог в Oracle, где вы хотите файлбыть написанным.Этот каталог / путь должен быть доступен и доступен для записи с сервера базы данных.

CREATE DIRECTORY UTL_FILE_DIR AS '/scratch/data/file_data';

2) Теперь получите доступ для чтения и записи в этот каталог.

grant READ, WRITE on UTL_FILE_DIR to <reporting_user>;

3) Код, который будет генерироватьфайл.

declare
    v_outfile  utl_file.file_type;
    v_file     varchar2(100);
    v_path     varchar2(100) := 'UTL_FILE_DIR';
                           -- alias for the directory where your text files generated at OS.
begin
    for d in ( select distinct department_name as dept from employees )  
    loop  
        v_file    := 'list_'||d.dept||'.txt';
        v_outfile := utl_file.fopen(v_path, v_file, 'w');
      for c in ( select employee_name from employees where department_name = d.dept )
      loop
       begin 
         utl_file.put_line(v_outfile,c.employee_name);                 
       end; 
      end loop;
        utl_file.fclose(v_outfile); 
    end loop;
end;
...