【问题标题】:Write data to flat file in a loop using UTL_FILE使用 UTL_FILE 在循环中将数据写入平面文件
【发布时间】:2016-09-07 18:50:57
【问题描述】:

我正在尝试将表 employees 中的员工姓名导出到平面文件中。平面文件应具有以下结构:

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;
/

存储过程循环运行。文件TMP_LOG.txt 是为表employees 中的每个人反复创建的。

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;

【问题讨论】:

    标签: oracle plsql oracle11g utl-file


    【解决方案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;
    /
    

    with 生成一个文件,其中包含:

    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 的任何过滤器。

    【讨论】:

    • 谢谢亚历克斯!正是我想要的。假设员工表包含数千行。我如何在 id 集合中传递它们而不必列出每一个?
    • @user3651825 - 这取决于您选择它们​​的标准。您可以让您的调用块从查询中填充一个集合,然后传递它。我添加了一个获得相同行的演示,我认为这更接近您的原始调用循环,但只有在您真的使用其他列来选择 ID 时才有意义。
    • 我将不得不阅读有关使用集合和用户定义的数据类型的内容。再次感谢!没有其他问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    相关资源
    最近更新 更多