在 pl/sql 脚本中处理非常大的字符串
Handle a very large string in pl/sql script
我正在尝试 运行 下面的代码,该代码读取 table A 的索引定义,以便在我 delete/create 之后可以在该脚本中再次创建它。当返回值 (ddl) 较小时,此脚本 运行 没问题,但在值较大且一行中有 140K 个字符的其他环境中,此脚本失败并出现以下错误。请注意,由于某些限制,我不能在这种情况下使用线轴。有人可以帮助解决这个问题或建议其他方法吗?
提前致谢。
"算术、数字、字符串、转换或约束错误
发生了。例如,如果尝试
将值 NULL 分配给声明为 NOT NULL 的变量,或者如果
尝试将大于 99 的整数分配给变量
声明 NUMBER(2)."
SET SERVEROUTPUT ON;
DECLARE
my_cursor SYS_REFCURSOR;
TYPE clob_array IS VARRAY(15) OF CLOB;
index_array clob_array := clob_array();
v_clob CLOB;
--index_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
OPEN my_cursor FOR 'select replace(dbms_metadata.get_ddl (''INDEX'', index_name), ''"C",'', '''')
from user_indexes
where table_name = ''A''';
LOOP FETCH my_cursor INTO v_clob;
EXIT WHEN my_cursor%NOTFOUND;
index_array.extend;
index_array(index_array.count) := v_clob;
dbms_output.put_line(index_array(index_array.count));
END LOOP;
CLOSE my_cursor;
END;
/
我模拟了这个问题,你得到这个错误是因为 dbms_output.put_line
在服务器端显示 output.Try 切换到 UTL_FILE
或者尝试任何 alternatives
顺带一提,代码可以简化为:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
dbms_output.put_line(substr(index_array(index_array.count), 1, 32767));
end loop;
end;
我使用 substr()
将传递给 dbms_output.put_line
的值限制为它的 documented limit。您可以通过将文本拆分成更小的块来解决它,并且可能找到位置 32767 之前最后一个空白 space 的位置以避免拆分单词。
这是我想出的:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
procedure put_line
( p_text clob )
is
max_len constant simple_integer := 32767;
line varchar2(max_len);
remainder clob := p_text;
begin
while dbms_lob.getlength(remainder) > max_len loop
line := dbms_lob.substr(remainder,max_len);
line := substr(line, 1, instr(line, ' ', -1));
remainder := substr(remainder, length(line) +1);
dbms_output.put_line(line);
end loop;
if length(trim(remainder)) > 0 then
dbms_output.put_line(remainder);
end if;
end put_line;
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
put_line(index_array(index_array.count));
end loop;
end;
我正在尝试 运行 下面的代码,该代码读取 table A 的索引定义,以便在我 delete/create 之后可以在该脚本中再次创建它。当返回值 (ddl) 较小时,此脚本 运行 没问题,但在值较大且一行中有 140K 个字符的其他环境中,此脚本失败并出现以下错误。请注意,由于某些限制,我不能在这种情况下使用线轴。有人可以帮助解决这个问题或建议其他方法吗?
提前致谢。
"算术、数字、字符串、转换或约束错误 发生了。例如,如果尝试 将值 NULL 分配给声明为 NOT NULL 的变量,或者如果 尝试将大于 99 的整数分配给变量 声明 NUMBER(2)."
SET SERVEROUTPUT ON;
DECLARE
my_cursor SYS_REFCURSOR;
TYPE clob_array IS VARRAY(15) OF CLOB;
index_array clob_array := clob_array();
v_clob CLOB;
--index_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
OPEN my_cursor FOR 'select replace(dbms_metadata.get_ddl (''INDEX'', index_name), ''"C",'', '''')
from user_indexes
where table_name = ''A''';
LOOP FETCH my_cursor INTO v_clob;
EXIT WHEN my_cursor%NOTFOUND;
index_array.extend;
index_array(index_array.count) := v_clob;
dbms_output.put_line(index_array(index_array.count));
END LOOP;
CLOSE my_cursor;
END;
/
我模拟了这个问题,你得到这个错误是因为 dbms_output.put_line
在服务器端显示 output.Try 切换到 UTL_FILE
或者尝试任何 alternatives
顺带一提,代码可以简化为:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
dbms_output.put_line(substr(index_array(index_array.count), 1, 32767));
end loop;
end;
我使用 substr()
将传递给 dbms_output.put_line
的值限制为它的 documented limit。您可以通过将文本拆分成更小的块来解决它,并且可能找到位置 32767 之前最后一个空白 space 的位置以避免拆分单词。
这是我想出的:
declare
type clob_array is table of clob;
index_array clob_array := clob_array();
procedure put_line
( p_text clob )
is
max_len constant simple_integer := 32767;
line varchar2(max_len);
remainder clob := p_text;
begin
while dbms_lob.getlength(remainder) > max_len loop
line := dbms_lob.substr(remainder,max_len);
line := substr(line, 1, instr(line, ' ', -1));
remainder := substr(remainder, length(line) +1);
dbms_output.put_line(line);
end loop;
if length(trim(remainder)) > 0 then
dbms_output.put_line(remainder);
end if;
end put_line;
begin
for r in (
select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
from user_indexes
where table_name = 'A'
)
loop
index_array.extend;
index_array(index_array.count) := r.index_ddl;
put_line(index_array(index_array.count));
end loop;
end;