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

你可能感兴趣的:(代码技术)