1. 程式人生 > >oracle pl/sql 將資料寫入Csv檔案 且以附件的形式傳送郵件

oracle pl/sql 將資料寫入Csv檔案 且以附件的形式傳送郵件

內容介紹

這篇文章將介紹,oracle 中如何將資料庫中查找出來的資料寫入csv 檔案,且將這個csv 檔案 ,用郵件以附件的形式傳送出去。如果你也想實現這個功能,請參考以下程式碼。如果想用sqlplus 方式實現,請參考我的另外一篇文章:sqlplus spool 生成csv檔案,且用郵件傳送附件檔案

將資料寫入csv

//description
procedure WRITE_DATA_CSV(
P_START_DATE in date,
P_END_DATE in date,
IC_FILE_NAME in VARCHAR2 --檔名
)as

V_CURSOR number; --遊標
SQLSTRING clob;
V_RUN_DATE varchar2(20);
V_EMPLOYEE_NUMBER varchar2(20);
v_FULL_NAME varchar2(20);
V_COUNT int;
L_CNT number:=0 ;
L_DESCTAB DBMS_SQL.DESC_TAB;
L_SEPARATOR varchar(1); --分隔符 ,每列用|分割開
P_FILENAME varchar2(50) ;
L_OUTPUT UTL_FILE.FILE_TYPE;
L_COLUMNVALUE varchar2(200);
line_conv raw(2000);

begin

/*sql語句過長,超過32767,可以拼接
eg:
SQLSTRING clob;
SQLSTRING1 clob;
SQLSTRING2 clob;
sqlstring1:=‘select *’;
sqlstring2:='
from XXX’;
SQLSTRING:=SQLSTRING1||SQLSTRING2;
*/

sqltitle:=‘select ‘‘aa’’,’‘bb’’,’‘cc’’,’‘dd’’,’‘ee’’ from dual’;
SQLSTRING:=‘select empno ,emp_name ,emp_birthday,emp_grade,emp_address from emp_info where effective_date between :CP_START_DATE and :CP_end_DATE’;

P_FILENAME := IC_FILE_NAME;

–建立路徑(伺服器上存放檔案路徑 ODPDIR)
l_output := utl_file.fopen(‘ODPDIR’,p_filename,‘w’,max_linesize => 2500); --max_linesize 行的長度(如果行過長,需要設定)

V_CURSOR :=DBMS_SQL.OPEN_CURSOR;
–解析動態SQL語句
DBMS_SQL.PARSE(V_CURSOR,sqltitle,DBMS_SQL.native);

L_SEPARATOR:=’’;

–寫入標題
DBMS_SQL.DESCRIBE_COLUMNS(V_CURSOR,L_CNT,L_DESCTAB);

for I in 1…L_DESCTAB.COUNT LOOP
–UTL_FILE.PUT(L_OUTPUT,L_SEPARATOR || L_DESCTAB(I).COL_NAME); --輸出表欄位
DBMS_SQL.DEFINE_COLUMN(V_CURSOR, I, L_COLUMNVALUE, 2000); --DEFINE_COLOUMN:定義欄位變數,其值對應於指定遊標中某個位置元素的值
L_SEPARATOR := ‘|’;
end LOOP;

V_COUNT := DBMS_SQL.execute(V_CURSOR);
WHILE (DBMS_SQL.FETCH_ROWS(V_CURSOR) > 0) LOOP – FETCH_ROWS:從指定的遊標中取出記錄
L_SEPARATOR:=’’;
for I in 1 … L_CNT LOOP
DBMS_SQL.column_value(V_CURSOR, I, L_COLUMNVALUE); --COLUMN_VALUE:返回遊標中指定位置的元素
UTL_FILE.PUT(L_OUTPUT,L_SEPARATOR ||L_COLUMNVALUE); --every column value in double quote (") convert(L_SEPARATOR ||L_COLUMNVALUE,‘ZHS16GBK’,‘UTF8’)
L_SEPARATOR := ‘|’;
end LOOP;
UTL_FILE.FFLUSH(L_OUTPUT);-- FFLUSH強制將緩衝的資料寫入檔案
UTL_FILE.PUT(L_OUTPUT,CHR(13)||CHR(10));
end loop;

–寫入內容
–解析動態SQL語
DBMS_SQL.PARSE(V_CURSOR,SQLSTRING,DBMS_SQL.native);

–繫結輸入引數,v_price的值傳給
DBMS_SQL.BIND_VARIABLE(V_CURSOR,’:CP_START_DATE’,P_START_DATE);
DBMS_SQL.BIND_VARIABLE(V_CURSOR,’:CP_END_DATE’,P_END_DATE);

L_SEPARATOR:=’’;

DBMS_SQL.DESCRIBE_COLUMNS(V_CURSOR,L_CNT,L_DESCTAB);
for I in 1…L_DESCTAB.COUNT LOOP
–UTL_FILE.PUT(L_OUTPUT,L_SEPARATOR || L_DESCTAB(I).COL_NAME); --輸出表欄位
DBMS_SQL.DEFINE_COLUMN(V_CURSOR, I, L_COLUMNVALUE, 2000); --DEFINE_COLOUMN:定義欄位變數,其值對應於指定遊標中某個位置元素的值
L_SEPARATOR := ‘|’;
end LOOP;

–UTL_FILE.PUT(L_OUTPUT,CHR(13)||CHR(10));
–UTL_FILE.NEW_LINE(L_OUTPUT,0);

V_COUNT := DBMS_SQL.execute(V_CURSOR);
WHILE (DBMS_SQL.FETCH_ROWS(V_CURSOR) > 0) LOOP – FETCH_ROWS:從指定的遊標中取出記錄
L_SEPARATOR:=’’;
for I in 1 … L_CNT LOOP
DBMS_SQL.column_value(V_CURSOR, I, L_COLUMNVALUE); --COLUMN_VALUE:返回遊標中指定位置的元素
UTL_FILE.PUT(L_OUTPUT,L_SEPARATOR ||L_COLUMNVALUE); --every column value in double quote (") convert(L_SEPARATOR ||L_COLUMNVALUE,‘ZHS16GBK’,‘UTF8’)
L_SEPARATOR := ‘|’;
end LOOP;
UTL_FILE.FFLUSH(L_OUTPUT);-- FFLUSH強制將緩衝的資料寫入檔案
UTL_FILE.PUT(L_OUTPUT,CHR(13)||CHR(10));
end loop;

dbms_sql.close_cursor(v_cursor); --CLOSE_CURSOR:關閉指定的遊標並釋放記憶體
utl_file.fclose( l_output); --CLOSE FILE

end ;

傳送郵件並且帶csv附件

procedure SEND_ATTACHMENT_EMAIL(
V_SUBJECT varchar2, --郵件主題
V_RECIPIENTS_list varchar2, --收件人郵箱
V_FILE_NAME varchar2, --附件檔名稱
V_SENDER varchar2 --發件人
)as
V_LOG VARCHAR2(100);
fil BFILE;
file_len PLS_INTEGER;
MAX_LINE_WIDTH PLS_INTEGER := 54;
buf RAW(2100);
amt BINARY_INTEGER := 672 * 3; /* ensures proper format; 2016 /
pos PLS_INTEGER := 1; /
pointer for each piece /
filepos PLS_INTEGER := 1; /
pointer for the file /
v_file_handle UTL_FILE.FILE_TYPE;
v_directory_name VARCHAR2(100) :=‘ODPDIR’;
v_line VARCHAR2(1000);
conn UTL_SMTP.CONNECTION; --utl_smtp.connection;–
mesg VARCHAR2(32767);
mesg_len NUMBER;
crlf VARCHAR2(2) := chr(13) || chr(10);
data RAW(2100);
chunks PLS_INTEGER;
len PLS_INTEGER := 1;
modulo PLS_INTEGER;
pieces PLS_INTEGER;
err_num NUMBER;
err_msg VARCHAR2(100);
V_MIME_TYPE_BIN varchar2(30) := ‘application/pdf’;
FILENM varchar2(50) := v_file_name; /
binary file attachment */

–選取表中的郵箱地址
cursor cur_maildress(i_RECIPIENTS_list varchar2) is
SELECT PURF.ROW_LOW_RANGE_OR_NAME,
ROW_NUMBER() OVER (PARTITION BY PURF.ROW_LOW_RANGE_OR_NAME ORDER BY PURF.ROW_LOW_RANGE_OR_NAME,PUC.USER_COLUMN_NAME) SEQ,
PUCIF.VALUE ADDRESSEE
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 PUT.USER_TABLE_NAME=i_RECIPIENTS_list
and PUC.USER_COLUMN_NAME=‘MAIL’
and sysdate between PUCIF.effective_start_date and PUCIF.effective_end_date;

BEGIN
/* Fill in the variable information for the e-mail /
/
Comment out the sections you don’t want /
/
The only information required is one recipient /
BEGIN
/
Fill in to-from and subject info here */
for CUR_MAIL in CUR_MAILDRESS(V_RECIPIENTS_LIST) LOOP
BEGIN
CONN := MEL_SEND_MAIL.BEGIN_MAIL(
SENDER => V_SENDER,
recipients => cur_mail.ADDRESSEE,
subject => V_SUBJECT,
MIME_TYPE => MEL_SEND_MAIL.MULTIPART_MIME_TYPE);
EXCEPTION
when OTHERS then
V_LOG := ‘Send mail to ‘||cur_mail.ADDRESSEE||’ error.’;
end;
end loop;
END begin_mail;

BEGIN
MEL_SEND_MAIL.ATTACH_TEXT(CONN => CONN,
data => 'Dear Jane ’ || CRLF || CRLF ||
‘The atatchment is GDW data. Please pay attention to it.’
|| CRLF || CRLF || ‘Thanks.’,
mime_type => ‘text/html’);
END attach_text;
BEGIN
MEL_SEND_MAIL.begin_attachment( conn => conn, mime_type => v_mime_type_bin,
inline => TRUE, filename => filenm, --‘test4.pdf’
transfer_enc => ‘base64’);
BEGIN
–dbms_output.put_line ('get values for filename ’ ||filenm);
fil := BFILENAME(‘ODPDIR’, filenm);
–dbms_output.put_line (‘Got handle’);
file_len := dbms_lob.getlength(fil);
modulo := mod(file_len, amt);
pieces := trunc(file_len / amt);
if (modulo <> 0) then
pieces := pieces + 1;
end if;
/* Open the file */
dbms_lob.fileopen(fil, dbms_lob.file_readonly);

dbms_lob.read(fil, amt, filepos, buf);
data := NULL;

FOR i IN 1…pieces LOOP
filepos := i * amt + 1;
file_len := file_len - amt;
data := utl_raw.concat(data, buf);
chunks := trunc(utl_raw.length(data) / MAX_LINE_WIDTH);
IF (i <> pieces) THEN
chunks := chunks - 1;
END IF;
MEL_SEND_MAIL.write_raw( conn => conn,
message => utl_encode.base64_encode(data ) );
–dbms_output.put_line( utl_encode.base64_encode(data));
– IF (pos + len <= utl_raw.length(data)) THEN
– data := utl_raw.substr(data, pos + len);
– ELSE
data := NULL;
– END IF;
if (file_len < amt and file_len > 0) then
amt := file_len;
end if;
dbms_lob.read(fil, amt, filepos, buf);
END LOOP;
END;

dbms_lob.fileclose(fil);

MEL_SEND_MAIL.end_attachment(conn => conn );
END begin_attachment;

MEL_SEND_MAIL.end_mail(conn => conn);

EXCEPTION
when no_data_found then
MEL_SEND_MAIL.end_attachment( conn => conn );
dbms_lob.fileclose(fil);
when others then
MEL_SEND_MAIL.end_attachment( conn => conn );
err_num := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 100);
dbms_output.put_line('Error number is ’ || err_num);
dbms_output.put_line('Error message is ’ || err_msg);
–dbms_lob.fileclose(fil);
end;

ps:發郵件的程式碼請參考,這個更全面:
link: https://support.oracle.com/epmos/faces/SearchDocDisplay?_adf.ctrl-state=3qwpl3gn8_9&_afrLoop=336542731263695#FIX