【发布时间】:2016-08-15 17:14:04
【问题描述】:
我有一个 450 MB 的 xml 文件,我想将它插入到 Oracle 表的 Blob 列中。我尝试将文件内容作为字符串插入,但它说“字符串文字太长”。任何人都可以建议一种优雅的方式插入表格。 提供:我在数据库服务器中没有目录访问权限,我在本地系统中有 xml 文件
【问题讨论】:
标签: xml database oracle plsql blob
我有一个 450 MB 的 xml 文件,我想将它插入到 Oracle 表的 Blob 列中。我尝试将文件内容作为字符串插入,但它说“字符串文字太长”。任何人都可以建议一种优雅的方式插入表格。 提供:我在数据库服务器中没有目录访问权限,我在本地系统中有 xml 文件
【问题讨论】:
标签: xml database oracle plsql blob
假设您搜索了一下并偶然发现了 search result:您找到了一个带有 PL/SQL 代码的页面。
CREATE OR REPLACE DIRECTORY test_dir AS '<path_on_db_server>';
DECLARE
l_bfile BFILE;
l_blob BLOB;
BEGIN
-- this depends on your table definition, col1 being the BLOB column
INSERT INTO tab1 (col1, col2) VALUES (empty_blob(), 'test1')
RETURN col1 INTO l_blob;
l_bfile := BFILENAME('test_dir', 'my.xml');
DBMS_LOB.fileopen(l_bfile, Dbms_Lob.File_Readonly);
DBMS_LOB.loadfromfile(l_blob, l_bfile, DBMS_LOB.getlength(l_bfile));
DBMS_LOB.fileclose(l_bfile);
COMMIT;
END;
然后你试试(在你把你的test.xml 文件放在服务器上<path_on_db_server> 并确保oracle 用户可以访问该文件之后)。
【讨论】:
您可以将 xml 文件转换为执行适当制作的匿名 plsql 块的 sql 脚本。将此脚本加载到数据库中将填充 blob。
基本思想是将 xml 文件拆分为 2000 个字符的块。第一个块可以直接插入到目标表的 blob 列中。彼此将通过利用dbms_lob.fragment_insert 包过程的更新语句添加。 !!!警告:不建议这样做!。最好让 dba 为您加载它!
示例:
假设:
dbms_lob.fragment_insert 最多可处理 32767,但是,涉及的其他工具(例如 sqlplus)可能对行长度有更严格的限制。代码:
declare
l_b BLOB;
begin
insert
into
t_target ( c_pk, c_blob )
values ( 42, utl_raw.cast_to_raw('<This literal contains the first 2000 (chunksize) characters of the xml file>') )
returning c_blob
into l_b
;
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 2000>'));
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 4000>'));
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 6000>'));
...
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains the last chunk>'));
commit;
end;
/
show err
准备工作
您需要确保您的 xml 文件中没有出现单引号。 否则生成的plsql代码会包含语法错误。
如果不使用单引号作为属性值分隔符,只需将它们替换为数字实体&x#28;。
创建大量匿名 plsql
在this SO question 中介绍了定期将数据插入文件的方法,in this answer 概述了最灵活的方法。插入以下字符串,而不是换行符:
"'));\n dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('"
匿名plsql的其余部分可以手动复制/编写。
警告
照原样,脚本大小将与原始 xml 大小相同,plsql 块将包含 200k+ 行。您很可能会遇到所涉及工具的一些限制。但是,可以将脚本拆分为任意数量的块,如下所示:
declare
l_b BLOB;
begin
select c_blob
into l_b
from t_target
where c_pk = 42
;
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset <k>*2000>'));
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+1)*2000>'));
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+2)*2000>'));
...
dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+<n_k>)*2000>'));
end;
/
show err
再一次:!!!警告:不建议这样做!。最好让 dba 为您加载它!
【讨论】:
如何编写任何语言的小程序,它能够读取文件并将查询插入到您的表中。
【讨论】: