最近项目上有位同事遇到这样一个问题
在PLSQL中用UTL_FILE的包写文件时,由于一行的数据过大(超过Vachar2的定义长度32k,也就是32767byte)报错,来求助帮忙想办法解决。(出力的文件是个CSV文件,第一行为行头,后面是数据,行头里都是日语项目名,每个项目名有特别特别多和长)
刚开始想到,既然是Vachar2的定义长度的限制,能不能把行头分成2行输出,然后输出文件后再把2行行头合并呢,因为这次是一个工具的程序,在plsql中写出CSV文件,然后之后会用VBA程序读入文件内容到Excel的模板里。
所以想到PLSQL输出文件时先把出2行,再在VBA里合并就好了,可是经过调查发现因为工具太过复杂,如果这个做需要大量的改动工作量。
后来突然想到既然是Vachar2的定义长度的限制,能不能把头行内容改成CLOB类型输出到一行再输出数据呢,试验了下这样改动可以减少大量的工具改造。做法如下:
DECLARE
l_directory VARCHAR2(20) := 'u01/path';--这里是文件输出路径
l_file_name VARCHAR2(20) := 'test.csv';--这里是文件输出文件
l_file utl_file.file_type;
l_clob CLOB;--原来出错时用的是VARCHAR2(32767)
l_len BINARY_INTEGER ;
l_pos BINARY_INTEGER ;
l_buffer VARCHAR2(32767);
l_amount BINARY_INTEGER ;
BEGIN
l_pos := 1;
l_amount := 1024;
--此循环只是为了模拟超过32k长的行头,放入l_clob 变量里。
FOR i IN 1 .. 5000
LOOP
l_clob := l_clob || '[共通]20kV・30kV力率修正前基本料金';
END LOOP;
--此处是为了输出行头后换行
l_clob := l_clob||CHR(13)||CHR(10);
--select dbms_lob.getlength(l_clob) into l_len from dual;
l_len := dbms_lob.getlength(l_clob);
--此处不用W方式用WB
l_file := utl_file.fopen(l_directory, l_file_name, 'wb', 32767);
WHILE l_pos < l_len LOOP
dbms_lob.READ(l_clob, l_amount, l_pos, l_buffer);
utl_file.put_raw(l_file, utl_raw.cast_to_raw(l_buffer));
utl_file.fflush(l_file);
l_pos := l_pos + l_amount;
END LOOP;
utl_file.fclose(l_file);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
/