说明:
将oracle下含有大字段(clob)列的大量表数据导出到本地可读文件(如txt或csv)。
处理过程:
先尝试在客户端(如dbeaver等)程序中进行查询,再复制粘贴结果集至excel或txt文本中。由于需要导出的表有200多个,且clob中的内容是html格式,单行clob列记录的内容可能达到几千上万个字符,再加上每张表有大约几十万条这样的数据,导致查询消耗很长时间,而在加载全部数据准备进行复制时,由于本地缓存空间不足,客户端直接hung住。
之后又考虑对单个表先查询出结果再粘贴,这样结果集会小很多,但需要进行上百次这样的重复操作,工作量很大。
再然后又想到用以前提到的方法,使用oracle的utl_file包来处理,详见《oracle导出大批量数据为csv或txt文件》,由于utl_file包只能支持varchar类型,也就是当字段中超过4000字符就直接报错了。但我们可以通过分段截取的方式进行处理来规避这个问题。
之后发现在某些客户端程序中有专门的数据导出至本地文本的功能,处理速度还是比较可观的。但由于这个客户端软件不是免费开源的,无法成为通用解决方案。
最后通过研究和实验,我找到一个比较方便的方法,该方法只适用于12C之后的版本:使用DBMS_LOB包中的DBMS_LOB.CLOB2FILE函数来处理。具体流程如下:
处理流程:
1)在DB服务器上创建目录:
mkdir /opt/temp
2)在DB服务器数据库中创建directory:
sqlplus / as sysdba
create directory temp as ‘/opt/temp’;
grant read,write on directory temp to cqiwen;
3)使用cqiwen用户登录,执行以下sql代码:
declare
buf CLOB;
tmptxt CLOB := '';
begin
DBMS_LOB.CREATETEMPORARY(tmptxt, true);
DBMS_LOB.OPEN(tmptxt, DBMS_LOB.LOB_READWRITE);
for i in 1 .. 10 loop
buf := 'hello,中国万岁!12345678'||CHR(13);
DBMS_LOB.append(tmptxt, buf);
end loop;
DBMS_LOB.CLOSE(tmptxt);
DBMS_LOB.CLOB2FILE(cl => tmptxt,
flocation => 'TEMP',
fname => 'test_get_clob.txt',
openmode => 'wb');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
end;
/
复制
4)将 /opt/temp 下生成的test_get_clob.txt文件拷贝到本地,用文本工具即可打开查看。
业务实现:
修改上面的代码块,创建游标,游标中储存对多张表进行union all的查询结果集,然后依次取出游标中的每行记录,用游标循环替换掉上面代码块中的for循环,使用相同的方法进行写入即可。
以下是伪代码:
declare
buf CLOB;
tmptxt CLOB := '';
cursor cur1 as select id,content from tab1
union all select id,content from tab2
union all select id,content from tab3
union all ......;
v_c cur1%rowtype;
begin
DBMS_LOB.CREATETEMPORARY(tmptxt, true);
DBMS_LOB.OPEN(tmptxt, DBMS_LOB.LOB_READWRITE);
open cur1; loop
fetch cur1 into v_c;
exit when cur1%notfound;
buf := v_c.id||','||v_c.content||CHR(13);
DBMS_LOB.append(tmptxt, buf);
end loop; close cur1;
DBMS_LOB.CLOSE(tmptxt);
DBMS_LOB.CLOB2FILE(cl => tmptxt,
flocation => 'TEMP',
fname => 'test_get_clob.txt',
openmode => 'wb');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
end;
/
复制