1. 程式人生 > >oracle ebs + PL/SQL實現將查詢出來的資料儲存為csv格式檔案,並定期上傳到FTP伺服器學習總結

oracle ebs + PL/SQL實現將查詢出來的資料儲存為csv格式檔案,並定期上傳到FTP伺服器學習總結

目的
oracle ebs + PL/SQL實現將查詢出來的資料儲存為csv格式檔案,並定期上傳到FTP伺服器。
用到oracle utl_file包,FTP檔案上傳
第一次接觸這種型別的任務,也是在網上查詢了很多參考資料才弄出來。
下面是具體的例子。
先在前臺配置請求:系統管理員→併發→程式→定義

系統管理員→併發→程式→定義
系統管理員→併發→程式→可執行
將該請求掛到相應的責任下
掛請求到責任
後臺資料庫程式碼
建立包頭

create or replace PACKAGE ML_OPCM_INFORMATION_UPLOAD AS
     procedure ML_OPCM_INFORMATION(  
           o_err_code OUT
NUMBER, o_err_msg OUT VARCHAR2, IC_TABLE_NAME in varchar2 , -- FTP伺服器列表 IC_ROW_NAME in varchar2 , --FTP伺服器行名 IC_FILE_NAME in varchar2 -- 檔名稱 )
;
END ML_OPCM_INFORMATION_UPLOAD;

包體

create or replace PACKAGE BODY ML_OPCM_INFORMATION_UPLOAD AS

PROCEDURE
SEND_OUTPUT( ic_output IN VARCHAR2) AS BEGIN fnd_file.put_line(fnd_file.output, ic_output); --dbms_output.put_line (ic_output); END SEND_OUTPUT; PROCEDURE SEND_LOG( ic_log IN VARCHAR2) AS BEGIN fnd_file.put_line(fnd_file.log, ic_log); --dbms_output.put_line (ic_log); END SEND_LOG; procedure
ML_OPCM_INFORMATION( o_err_code OUT NUMBER, o_err_msg OUT VARCHAR2, IC_TABLE_NAME in VARCHAR2 , -- FTP伺服器列表 IC_ROW_NAME in VARCHAR2 , --FTP伺服器行名 IC_FILE_NAME in VARCHAR2 -- 檔名稱 ) is l_conn UTL_TCP.connection; vc_ftp_server_host VARCHAR2(100) :=NULL; --伺服器地址 vc_ftp_server_port VARCHAR2(10) :=NULL; --埠 vc_ftp_account VARCHAR2(100) :=NULL; --使用者名稱 vc_ftp_password VARCHAR2(100) :=NULL; --密碼 l_output utl_file.file_type; l_theCursor integer default dbms_sql.open_cursor; --OPEN_CURSOR: 返回新遊標的ID值 l_columnValue VARCHAR2(2000); l_status integer; l_colCnt number default 0; l_separator VARCHAR2(1) ; p_filename VARCHAR2(50) ; l_cnt number default 0; p_query varchar2(4000); l_desctbl DBMS_SQL.DESC_TAB; date_famart VARCHAR2(10) default 'YYYY-MM-DD'; CURSOR cur_ftp_info(ic_cur_table_name VARCHAR2,ic_cur_row_name VARCHAR2) IS SELECT put.user_table_name table_name, puc.user_column_name column_name, purf.row_low_range_or_name row_name, pucif.VALUE p_value FROM pay_user_tables put, pay_user_columns puc, pay_user_rows_f purf, pay_user_column_instances_f pucif WHERE put.user_table_id = puc.user_table_id AND put.user_table_id = purf.user_table_id AND pucif.user_row_id = purf.user_row_id AND pucif.user_column_id = puc.user_column_id AND purf.row_low_range_or_name = ic_cur_row_name AND put.user_table_name = ic_cur_table_name ; begin p_filename := 'TERMINATION_EMP.CSV'; -- 先要建立路徑 create or replace directory UTL_FILE_DIR as '/tmp'; begin l_output := utl_file.fopen('UTL_FILE_DIR', p_filename, 'w'); exception when others then SEND_LOG('Error when open the file from UTL_FILE_DIR :'||SQLCODE||'-'||SQLERRM); end; BEGIN --p_query定義為varchar2型別,如果超過varchar2最大值可以用clob型別 p_query :='select * from emp '; -- DBMS_OUTPUT.PUT_LINE(p_query); --PARSE:解析要執行的語句 -- p_query sql語句 dbms_sql.parse(l_theCursor, p_query, dbms_sql.native ); DBMS_SQL.DESCRIBE_COLUMNS(l_theCursor, l_colCnt, l_desctbl); --DUMP TABLE COLUMN NAME FOR I IN 1 .. l_colCnt LOOP UTL_FILE.PUT(l_output,l_separator || l_desctbl(I).COL_NAME ); --輸出表欄位 DBMS_SQL.DEFINE_COLUMN(l_theCursor, I, l_columnValue, 4000); --DEFINE_COLOUMN:定義欄位變數,其值對應於指定遊標中某個位置元素的值 l_separator := ','; END LOOP; --記事本開啟會換行 chr(13),chr(10)分別對應\r,\n UTL_FILE.put(l_output,chr(13)||chr(10)); UTL_FILE.NEW_LINE(l_output,0); --UTL_FILE.NEW_LINE(l_output); --這種方式記事本開啟檔案不換行 --EXECUTE THE QUERY STATEMENT L_STATUS := DBMS_SQL.EXECUTE(l_theCursor); --EXECUTE:執行指定的遊標 --DUMP TABLE COLUMN VALUE WHILE (DBMS_SQL.FETCH_ROWS(l_theCursor) > 0) LOOP -- FETCH_ROWS:從指定的遊標中取出記錄 l_separator := ''; FOR I IN 1 .. l_colCnt LOOP DBMS_SQL.COLUMN_VALUE(l_theCursor, I, l_columnValue); --COLUMN_VALUE:返回遊標中指定位置的元素 UTL_FILE.PUT(l_output,l_separator || l_columnValue ); l_separator := ','; END LOOP; UTL_FILE.put(l_output,chr(13)||chr(10)); UTL_FILE.NEW_LINE(l_output,0); --UTL_FILE.NEW_LINE(l_output); END LOOP; --下面這部分為另外一種寫法,也可行 -- for i in 1 .. 255 loop -- begin -- dbms_sql.define_column( l_theCursor, i,l_columnValue, 2000 ); --DEFINE_COLOUMN:定義欄位變數,其值對應於指定遊標中某個位置元素的值 -- l_colCnt := i; -- exception -- when others then -- if ( sqlcode = -1007 ) then exit; -- else -- raise; -- end if; -- end; -- end loop; -- DBMS_OUTPUT.PUT_LINE('l_colCnt: '||l_colCnt); -- dbms_sql.define_column( l_theCursor, 1, l_columnValue,2000 ); -- -- l_status := dbms_sql.execute(l_theCursor); --EXECUTE:執行指定的遊標 -- --EmpID, First, PreferredName, Middle, Last, Gender, DateOfBirth ,OrigHireDate, LastHireDate, JobCode, JobTitle, -- --SupervisorID ,SupvName ,EmailAddress ,WrkPhoneNo, WrkLoc, TermDate ,Business Group, ITAR Compliant ,MobilePhoneNo , -- --FuncReportsTo ,Department ,AltTitle, MorE, Mailstop, Company, FullorPartTime, AD Acct_NTUserID -- -- utl_file.put( l_output, 'Empid,First,PreferredName,Middle,last,Gender,DateOfBirth,OrigHireDate,LastHireDate,JobCode,JobTitle,SupervisorID,SupvName,EmailAddress,WrkPhoneNo,WrkLoc,TermDate,Business Group,ITAR Compliant,MobilePhoneNo,FuncReportsTo,Department,AltTitle,MorE,Mailstop,Company,FullorPartTime,AD Acct_NTUserID,BANKNAME,BANKBRANCHNAME, BANKACCNAME, BANKACCNUMBER, BANKACCCURRENCY'); -- utl_file.new_line( l_output ); ---- utl_file.put_line( l_output, 'EmpID,First,PreferredName,Middle,Last,Gender,DateOfBirth,OrigHireDate,LastHireDate,JobCode,JobTitle,SupervisorID,SupvName,EmailAddress,WrkPhoneNo,WrkLoc,TermDate,Business Group,ITAR Compliant,MobilePhoneNo,FuncReportsTo,Department,AltTitle,MorE,Mailstop,Company,FullorPartTime,AD Acct_NTUserID'); -- -- loop -- exit when ( dbms_sql.fetch_rows(l_theCursor) <= 0 ); -- FETCH_ROWS:從指定的遊標中取出記錄 -- l_separator := ''; -- for i in 1 .. l_colCnt loop -- dbms_sql.column_value( l_theCursor, i,l_columnValue ); -- utl_file.put( l_output, l_separator ||l_columnValue); --COLUMN_VALUE:返回遊標中指定位置的元素 -- l_separator := ','; -- end loop; -- utl_file.put(l_output, ' '); -- utl_file.new_line( l_output ); -- l_cnt := l_cnt+1; -- end loop; dbms_sql.close_cursor(l_theCursor); --CLOSE_CURSOR:關閉指定的遊標並釋放記憶體 utl_file.fclose( l_output ); --CLOSE FILE EXCEPTION WHEN OTHERS THEN SEND_LOG('Error when output file :'||SQLCODE||'-'||SQLERRM); RAISE; END; -------獲取ftp伺服器資訊,這裡我開始在前臺有定義一個表結構和表值來儲存伺服器資訊 BEGIN FOR cur_temp IN cur_ftp_info(ic_table_name,ic_row_name) LOOP IF cur_temp.column_name ='FTP_SERVER_PASSWORD' THEN vc_ftp_password :=cur_temp.p_value; ELSIF cur_temp.column_name='FTP_SERVER_PORT' THEN vc_ftp_server_port :=cur_temp.p_value; ELSIF cur_temp.column_name='FTP_SERVER_ACCOUNT' THEN vc_ftp_account :=cur_temp.p_value; ELSIF cur_temp.column_name='FTP_SERVER_HOST' THEN vc_ftp_server_host :=cur_temp.p_value; END IF; END LOOP; IF vc_ftp_password IS NULL OR vc_ftp_server_port IS NULL OR vc_ftp_account IS NULL OR vc_ftp_server_host IS NULL THEN SEND_OUTPUT('Can not get ftp server information: please check the value of table name,row name,form'); RAISE_APPLICATION_ERROR(-20001,'Error when get ftp server information:'||SQLCODE||'-'||SQLERRM); END IF; --ML_FTP 就是網上的ftp l_conn := ML_FTP.login(vc_ftp_server_host,vc_ftp_server_port,vc_ftp_account,vc_ftp_password); ML_FTP.binary(p_conn => l_conn); -- Binary模式不會對資料進行任何處理 ML_FTP.put(p_conn => l_conn, p_from_dir => 'UTL_FILE_DIR', --這裡的路徑名注意要用大寫 p_from_file => p_filename, --伺服器上的檔名 p_to_file => IC_FILE_NAME ); --想要在伺服器上生成的檔名稱 ML_FTP.logout(l_conn); utl_tcp.close_all_connections; SEND_OUTPUT('upload file to ftp completed.'); EXCEPTION WHEN OTHERS THEN SEND_LOG('Error when upload file to ftp:'||SQLCODE||'-'||SQLERRM); RAISE_APPLICATION_ERROR(-20001,'Error when upload file to ftp:'||SQLCODE||'-'||SQLERRM); END; END ML_OPCM_INFORMATION; END ML_OPCM_INFORMATION_UPLOAD;