在 Oracle table 中将大 xml 文件作为 blob 插入
Insert large xml file as as blob in oracle table
我有一个 450 MB xml 文件,我想将它插入到 Oracle table 的 Blob 列中。我尝试将文件内容作为字符串插入,但它显示 "string literal too long"。任何人都可以建议一种优雅的方式插入 table。
提供:我在数据库服务器中没有目录访问权限,我的本地系统中有 xml 文件
用任何语言编写能够读取文件并向您的 table 中插入查询的小程序如何?
假设您进行了一些搜索,偶然发现了一个 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 文件转换为 sql 脚本,执行适当制作的匿名 plsql 块。将此脚本加载到数据库中将填充 blob。
基本思路是将 xml 文件拆分为 2000 个字符的块。第一个块可以直接插入到目标 table 的 blob 列中。彼此将通过利用 dbms_lob.fragment_insert
包过程的更新语句添加。 !!!警告:这不是推荐的做法!。最好让 dba 为您加载它!
例子:
假设:
- 目标 table 有 2 列,pk 和 blob。
- pk 是 42。
- 2000 是被视为合适的样本块大小table。从技术上讲,
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, the most flexible approach being outlined in this answer中介绍。插入以下字符串而不是换行符:
"'));\n dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('"
剩下的匿名plsql可以手工copied/written
警告
照原样,脚本大小将与原始 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 为您加载它!
我有一个 450 MB xml 文件,我想将它插入到 Oracle table 的 Blob 列中。我尝试将文件内容作为字符串插入,但它显示 "string literal too long"。任何人都可以建议一种优雅的方式插入 table。 提供:我在数据库服务器中没有目录访问权限,我的本地系统中有 xml 文件
用任何语言编写能够读取文件并向您的 table 中插入查询的小程序如何?
假设您进行了一些搜索,偶然发现了一个 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 文件转换为 sql 脚本,执行适当制作的匿名 plsql 块。将此脚本加载到数据库中将填充 blob。
基本思路是将 xml 文件拆分为 2000 个字符的块。第一个块可以直接插入到目标 table 的 blob 列中。彼此将通过利用 dbms_lob.fragment_insert
包过程的更新语句添加。 !!!警告:这不是推荐的做法!。最好让 dba 为您加载它!
例子:
假设:
- 目标 table 有 2 列,pk 和 blob。
- pk 是 42。
- 2000 是被视为合适的样本块大小table。从技术上讲,
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, the most flexible approach being outlined in this answer中介绍。插入以下字符串而不是换行符:
"'));\n dbms_lob.fragment_insert ( l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('"
剩下的匿名plsql可以手工copied/written
警告
照原样,脚本大小将与原始 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 为您加载它!