2016-09-07 45 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