2016-09-07 91 views
0

我正试图将表employees中的员工名称导出为平面文件。该平面文件应具有以下结构:使用UTL_FILE在循环中将数据写入平面文件

HEADER 
DETAILS JACK 
DETAILS JUNE 
TRAILER 

我所挣扎的是我怎么能在一个循环中运行这个以单排的名字保存在同一文件中。我目前的脚本一次只能将一个名称导出到单独的文件中。由于文件名保持不变,因此每次执行过程时都会覆盖文件。

请注意,如果可能,我希望将文件名作为变量。

Create table Employees (Id number(10),Name varchar(40)) 

Insert into Employees values (1,'JOHN'); 
Insert into Employees values (2,'JACK'); 
Insert into Employees values (3,'JUNE'); 
----------------------- 

CREATE OR REPLACE Procedure PRINT_NAMES(aId  in Employees.Id%Type, 
             aFileName in varchar2) 

Is 

    fDirectory varchar(30) := 'SB1KK_TEMP'; 
    fName  Employees.name%Type; 

    pFile Utl_File.file_type; 
    fLine Varchar2(1024); 

Begin 



    pFile := UTL_FILE.fopen(fDirectory, aFileName, 'w'); 

    --File Header 
    fLine := RPAD('HEADER', 10) || To_char(trunc(sysdate), 'yyyymmdd') || '000000'; 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 

    --File Details - This Section must be run in a loop 
    Select Name into fName From Employees where id = aId; 
    fLine := RPAD('DETAILS', 10) || RPAD(' ', 50) || 
      To_char(trunc(sysdate), 'yyyymmdd') || RPAD(fName, 11); 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 


    --File Trailer 
    fLine := RPAD('TRAILER', 10) || To_char(trunc(sysdate), 'yyyymmdd') || '000000'; 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 
    UTL_FILE.fclose(pFile); 

End; 
/

存储过程运行在一个循环中。对于表employees中的每个人,文件TMP_LOG.txt被反复创建。

Begin 
    For IDS in (Select * From Employees Where id in (2,3)) 
    Loop 
    PRINT_NAMES(aId => IDS.ID, aFileName => 'TMP_LOG.TXT'); 
    End Loop; 
End; 

回答

1

您需要在程序中执行循环,因为代码中的注释已经建议,而不是在调用过程时。但是,这意味着你需要通过多个ID以简单的方式来做到这一点,如果你允许创建新的用户定义类型,是一个集合表。

CREATE Type EmployeeIds as Table of Number(10) 
/

然后你的过程声明变为:

CREATE OR REPLACE Procedure PRINT_NAMES(aIds  in EmployeeIds, 
             aFileName in varchar2) 

,你可以做一个游标循环:

For IDS in (Select * From Employees Where ID member of aIds) Loop 
    fLine := RPAD('DETAILS', 10) || RPAD(' ', 50) || 
      To_char(trunc(sysdate), 'yyyymmdd') || RPAD(IDS.Name, 11); 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 
    End Loop; 

你不需要fname局部变量。

这么干脆变成:

CREATE OR REPLACE Procedure PRINT_NAMES(aIds  in EmployeeIds, 
             aFileName in varchar2) 

Is 

    fDirectory varchar(30) := 'SB1KK_TEMP'; 

    pFile Utl_File.file_type; 
    fLine Varchar2(1024); 

Begin 



    pFile := UTL_FILE.fopen(fDirectory, aFileName, 'w'); 

    --File Header 
    fLine := RPAD('HEADER', 10) || To_char(trunc(sysdate), 'yyyymmdd') || '000000'; 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 

    --File Details - This Section must be run in a loop 
    For IDS in (Select * From Employees Where ID member of aIds) Loop 
    fLine := RPAD('DETAILS', 10) || RPAD(' ', 50) || 
      To_char(trunc(sysdate), 'yyyymmdd') || RPAD(IDS.Name, 11); 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 
    End Loop; 

    --File Trailer 
    fLine := RPAD('TRAILER', 10) || To_char(trunc(sysdate), 'yyyymmdd') || '000000'; 
    UTL_FILE.put_line(pFile, convert(fLine, 'WE8ISO8859P1', 'UTF8')); 
    UTL_FILE.fclose(pFile); 

End; 
/

然后你ID的集合调用它,使用相同的UDT:

Begin 
    PRINT_NAMES(aIds => EmployeeIds(2,3), aFileName => 'TMP_LOG.TXT'); 
End; 
/

与生成包含一个文件:

HEADER 20160907000000 
DETAILS              20160907JACK 
DETAILS              20160907JUNE 
TRAILER 20160907000000 

您可以创建一个集合变量,然后将其填入该过程,例如:

Declare 
    lIds EmployeeIds; 
Begin 
    -- populate the collection from the table using criteria you need 
    Select ID Bulk Collect Into lIds From EmployeesX Where ID in (2,3); 
    PRINT_NAMES(aIds => lIds, aFileName => 'TMP_LOG.TXT'); 
End; 
/

...使用您想要选择要包含的ID的任何过滤器。

+0

谢谢Alex!正是我在找什么。假设employees表拥有数千行。如何将它们传递给ID收集而无需列出单独的EVRE? – MrM

+0

@ user3651825 - 取决于您用来选择它们的标准。你可以让你的调用块从查询中填充一个集合,然后传递它。我已经添加了一个获得相同行的演示,这更接近您原来的调用循环,但这只有在您真的使用其他列选择ID时才有意义。 –

+0

我将不得不阅读关于集合和用户定义的数据类型的使用。再次感谢!没有更多的问题。 – MrM