如何在一个循环中假脱机到多个文件?

Posted

技术标签:

【中文标题】如何在一个循环中假脱机到多个文件?【英文标题】:How to spool to multiple files within a loop? 【发布时间】:2019-04-08 14:54:22 【问题描述】:

我正在使用 Oracle 12c。

我有一张 EMPLOYEES 表,看起来像这样:

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

...等等...

关于如何实现这一点的任何想法?

谢谢。

【问题讨论】:

假脱机到单个文件。使用awk/sed或等效的方式将其拆分为多个文件 交替使用 UTL_FILE 将输出从 PL/SQL 写入文件。 【参考方案1】:

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

等等。在此示例中,有几个空文件,但如果我将初始查询加入这两个表,则不会有;因为您正在查询一个不会发生在您身上的表。

【讨论】:

【参考方案2】:

你可以使用 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;

【讨论】:

以上是关于如何在一个循环中假脱机到多个文件?的主要内容,如果未能解决你的问题,请参考以下文章

假脱机多个文件

在 sqlplus 中使用假脱机运行多个查询

从 pl/sql 块内立即执行的数据假脱机

linux环境下oracle如何选择特殊字符

如何使用 SQLPLUS 假脱机到 CSV 格式的文件?

如何使用 SQL Developer 假脱机到 CSV 文件?