SQL 另外 - 如何将大字符串传递给过程 CLOB 的参数
SQL Plus - how to pass big string to procedure CLOB's parameter
我有接收 XML:
的程序
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;
现在我正在做一个 bash 脚本,它将从服务器下载一些 XML 文件,对于每个文件,我将使用 SQL Plus 调用上述过程。
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml");
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
它适用于小文件,但对于大文件,我收到以下错误:
SQL*Plus: Release 12.1.0.2.0 Production on Thu Jun 8 18:28:19 2017
Copyright (c) 1982, 2016, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP
and Data Mining options
SQL> Input truncated to 7499 characters
SP2-0027: Input is too long (> 2499 characters) - line ignored
有什么办法可以发送那些大XML吗?
谢谢
您可以尝试循环遍历输入文件,一次附加 2.4k 个块,可能:
variable l_var clob;
exec :l_var := '';
-- loop here
exec :l_var := :l_var || '$chunk';
---
exec process_xml(:l_var);
而不是 shell 脚本,您还可以在 Java 中形成 clob,例如,逐行阅读 XML,它没有变量大小的限制。
您能否尝试在 bash 中压缩文件数据,然后使用 utl_compress 在 PLSQL 中解压缩?
类似于:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | gzip -f);
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
在 plsql 中:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
uncomp CLOB;
BEGIN
UTL_COMPRESS.lz_uncompress(src => xml, dst => uncomp);
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;
您可以将文件内容拆分成 SQL*Plus 可以接受的块,然后在匿名 PL/SQL 块中重新组合它们;这也将允许比字符串文字更长的值。例如:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | sed -r "s/(.{1,2000})/l_clob := l_clob || '';\n/g")
sqlplus -s -l myuser/mypass@myhost:1521/myscheme <<!EOF
set serveroutput on
declare
l_clob clob := '';
begin
${file}
PROCESS_XML(l_clob);
end;
/
exit
!EOF
EXECUTE
无论如何都是一个简单的匿名块的包装器,所以使用 heredoc 而不是 herestring 只会让你扩展它来做更多的事情。该块声明一个空的 CLOB,然后从文件中附加块 - 每个块都转换为如下所示:
l_clob := l_clob || '<up to 2000 chars>';
当SQL*Plus看到它时,构造的heredoc最终为:
set serveroutput on
declare
l_clob clob := '';
begin
l_clob := l_clob || '<first 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
...
l_clob := l_clob || '<last 2000 chars>';
PROCESS_XML(l_clob);
end;
/
exit
稍微修改您的程序,部分是为了验证传入的长度,部分是为了检查 XML 在该过程中没有被破坏:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started; CLOB length: '
|| length(xml));
DBMS_OUTPUT.PUT_LINE('XML processing started; converted XML length: '
|| length(xmltype(xml).getclobval()));
END;
/
使用该脚本处理大文件会得到输出:
XML processing started; CLOB length: 368104
XML processing started; converted XML length: 368104
PL/SQL procedure successfully completed.
当然,这会减慢速度; ~360k 文件在我的系统上花费了大约 13 秒。可能有比 sed
更快的机制,但原则仍然适用。
macOS 上的 sed
版本(需要 -E
而不是 GNU 的 -r
标志)似乎被限制为重复 255 次模式(通过 RE_DUMP_MAX
,在 limits.h
中设置,据我所知在运行时不可修改)。
您可以只使用一个下限:
file=$(curl -s "http://example.com/someFile.xml" | sed -E "s/(.{1,255})/l_clob := l_clob || '';\n/g")
实际上在 Linux 下也快得多,所以无论如何都是不错的选择。
在 macOS(El Cap,但对于 Sierra 可能相同)上进行进一步实验并尝试使转义换行符工作而不在输出中包含文字 n
或 \n
后,这会导致 PLS -00103,将实际的换行符放入:
似乎更容易
file=$(curl -s "http://example.com/someFile.xml" | sed -E "s/(.{1,255})/ l_clob := l_clob || '';\
/g")
我有接收 XML:
的程序CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;
现在我正在做一个 bash 脚本,它将从服务器下载一些 XML 文件,对于每个文件,我将使用 SQL Plus 调用上述过程。
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml");
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
它适用于小文件,但对于大文件,我收到以下错误:
SQL*Plus: Release 12.1.0.2.0 Production on Thu Jun 8 18:28:19 2017
Copyright (c) 1982, 2016, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP
and Data Mining options
SQL> Input truncated to 7499 characters
SP2-0027: Input is too long (> 2499 characters) - line ignored
有什么办法可以发送那些大XML吗?
谢谢
您可以尝试循环遍历输入文件,一次附加 2.4k 个块,可能:
variable l_var clob;
exec :l_var := '';
-- loop here
exec :l_var := :l_var || '$chunk';
---
exec process_xml(:l_var);
而不是 shell 脚本,您还可以在 Java 中形成 clob,例如,逐行阅读 XML,它没有变量大小的限制。
您能否尝试在 bash 中压缩文件数据,然后使用 utl_compress 在 PLSQL 中解压缩?
类似于:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | gzip -f);
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
在 plsql 中:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
uncomp CLOB;
BEGIN
UTL_COMPRESS.lz_uncompress(src => xml, dst => uncomp);
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;
您可以将文件内容拆分成 SQL*Plus 可以接受的块,然后在匿名 PL/SQL 块中重新组合它们;这也将允许比字符串文字更长的值。例如:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | sed -r "s/(.{1,2000})/l_clob := l_clob || '';\n/g")
sqlplus -s -l myuser/mypass@myhost:1521/myscheme <<!EOF
set serveroutput on
declare
l_clob clob := '';
begin
${file}
PROCESS_XML(l_clob);
end;
/
exit
!EOF
EXECUTE
无论如何都是一个简单的匿名块的包装器,所以使用 heredoc 而不是 herestring 只会让你扩展它来做更多的事情。该块声明一个空的 CLOB,然后从文件中附加块 - 每个块都转换为如下所示:
l_clob := l_clob || '<up to 2000 chars>';
当SQL*Plus看到它时,构造的heredoc最终为:
set serveroutput on
declare
l_clob clob := '';
begin
l_clob := l_clob || '<first 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
...
l_clob := l_clob || '<last 2000 chars>';
PROCESS_XML(l_clob);
end;
/
exit
稍微修改您的程序,部分是为了验证传入的长度,部分是为了检查 XML 在该过程中没有被破坏:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started; CLOB length: '
|| length(xml));
DBMS_OUTPUT.PUT_LINE('XML processing started; converted XML length: '
|| length(xmltype(xml).getclobval()));
END;
/
使用该脚本处理大文件会得到输出:
XML processing started; CLOB length: 368104
XML processing started; converted XML length: 368104
PL/SQL procedure successfully completed.
当然,这会减慢速度; ~360k 文件在我的系统上花费了大约 13 秒。可能有比 sed
更快的机制,但原则仍然适用。
macOS 上的 sed
版本(需要 -E
而不是 GNU 的 -r
标志)似乎被限制为重复 255 次模式(通过 RE_DUMP_MAX
,在 limits.h
中设置,据我所知在运行时不可修改)。
您可以只使用一个下限:
file=$(curl -s "http://example.com/someFile.xml" | sed -E "s/(.{1,255})/l_clob := l_clob || '';\n/g")
实际上在 Linux 下也快得多,所以无论如何都是不错的选择。
在 macOS(El Cap,但对于 Sierra 可能相同)上进行进一步实验并尝试使转义换行符工作而不在输出中包含文字 n
或 \n
后,这会导致 PLS -00103,将实际的换行符放入:
file=$(curl -s "http://example.com/someFile.xml" | sed -E "s/(.{1,255})/ l_clob := l_clob || '';\
/g")