值大于 32K 的子字符串 CLOB 值
Substring CLOB value with value more than 32K
请问,我正在尝试通过删除前 33 个字符和最后 2 个字符来对 clob 值进行子字符串处理,
我尝试使用以下简单代码,但返回错误:ORA-06502:PL/SQL:数字或值错误
DECLARE
p_Clob_Input CLOB := ''; --> value more than 32K
p_Clob_Output CLOB; --> input CLOB value after removing first 33 characters and last 2 characters
BEGIN
Dbms_Lob.Createtemporary(p_Clob_Output, FALSE);
Dbms_Lob.Writeappend(p_Clob_Output, Dbms_Lob.Getlength(p_Clob_Input)-35,Dbms_Lob.Substr(p_Clob_Input,Dbms_Lob.Getlength(p_Clob_Input)-2, 33));
END;
然后我尝试使用以下代码,它工作正常,但是,如果长度为 32001 或 64001,它仍然会失败,而且我觉得实现 objective 的代码太长了,
DECLARE
p_Clob_Index NUMBER;
p_Length NUMBER;
p_Chunk VARCHAR2(32000);
p_Clob_Input CLOB := ''; --> value more than 32K
p_Clob_Output CLOB; --> input CLOB value after removing first 33 characters and last 2 characters
BEGIN
Dbms_Lob.Createtemporary(p_Clob_Output, FALSE);
p_Length := Dbms_Lob.Getlength(p_Clob_Input);
p_Clob_Index := 1;
WHILE p_Clob_Index <= p_Length
LOOP
IF p_Clob_Index = 1
THEN
IF p_Length > 32000
THEN
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, 32000, 33);
ELSE
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, p_Length - 2, 33);
END IF;
ELSE
IF p_Clob_Index > p_Length - 32000
THEN
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, (p_Length - p_Clob_Index) - 1, p_Clob_Index);
ELSE
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, 32000, p_Clob_Index);
END IF;
END IF;
IF p_Clob_Index > p_Length - 32000
THEN
p_Clob_Index := p_Length + 1;
ELSE
p_Clob_Index := p_Clob_Index + 32000;
END IF;
Dbms_Lob.Writeappend(p_Clob_Output, Length(p_Chunk), p_Chunk);
END LOOP;
END;
感谢您的支持
我的数据库版本是 11.2.0.4.0
谢谢...
您的第一个代码块因值较大而失败,因为 the second argument to writeappend()
是 varchar2
,因此限制为 32k(在 PL/SQL 上下文中,4k 来自 SQL) .
您可以改用 the copy
procedure,它有 CLOB 参数:
DBMS_LOB.COPY (
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
src_lob IN CLOB CHARACTER SET dest_lob%CHARSET,
amount IN INTEGER,
dest_offset IN INTEGER := 1,
src_offset IN INTEGER := 1);
所以你可以这样做:
dbms_lob.createtemporary(p_clob_output, false);
dbms_lob.copy(p_clob_output, p_clob_input, dbms_lob.getlength(p_clob_input) - 35, 1, 34);
您的变量名(以及您用“值超过 32K”暗示的赋值,这也不适用于大字面值)表明您可能正在努力执行此操作;你可以这样做:
create or replace procedure your_proc (
p_clob_input in clob,
p_clob_output out clob,
p_trim_start number,
p_trim_end number
) as
begin
dbms_lob.createtemporary(p_clob_output, false);
dbms_lob.copy(
dest_lob => p_clob_output,
src_lob => p_clob_input,
amount => dbms_lob.getlength(p_clob_input) - (p_trim_start + p_trim_end),
dest_offset => 1,
src_offset => p_trim_start + 1);
end;
/
虽然这是否真的会让您的生活比直接调用 dbms_lob
更轻松,但仍有争议。
只需使用 SUBSTR
,因为它适用于 CLOB
超过 32767 个字符的值:
DECLARE
p_Clob_Input CLOB := EMPTY_CLOB();
p_Clob_Output CLOB;
p_start_offset PLS_INTEGER := 33;
p_end_offset PLS_INTEGER := 2;
BEGIN
FOR i IN 1 .. 10 LOOP
p_clob_input := p_clob_input || LPAD('1234567890', 4000, '1234567890');
END LOOP;
p_clob_output := SUBSTR(
p_clob_input,
p_start_offset + 1,
LENGTH( p_clob_input ) - p_start_offset - p_end_offset
);
DBMS_OUTPUT.PUT_LINE( 'Lengths:' );
DBMS_OUTPUT.PUT_LINE( LENGTH( p_clob_input ) );
DBMS_OUTPUT.PUT_LINE( LENGTH( p_clob_output ) );
DBMS_OUTPUT.PUT_LINE( 'Starts:' );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_input, 1, 40 ) );
DBMS_OUTPUT.PUT_LINE( LPAD( ' ', p_start_offset, ' ' ) || SUBSTR( p_clob_output, 1, 40 - p_start_offset ) );
DBMS_OUTPUT.PUT_LINE( 'Ends:' );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_input, 39961 ) );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_output, 39961 - p_start_offset ) );
END;
/
输出:
Lengths:
40000
39965
Starts:
1234567890123456789012345678901234567890
4567890
Ends:
1234567890123456789012345678901234567890
12345678901234567890123456789012345678
db<>fiddle here
请问,我正在尝试通过删除前 33 个字符和最后 2 个字符来对 clob 值进行子字符串处理,
我尝试使用以下简单代码,但返回错误:ORA-06502:PL/SQL:数字或值错误
DECLARE
p_Clob_Input CLOB := ''; --> value more than 32K
p_Clob_Output CLOB; --> input CLOB value after removing first 33 characters and last 2 characters
BEGIN
Dbms_Lob.Createtemporary(p_Clob_Output, FALSE);
Dbms_Lob.Writeappend(p_Clob_Output, Dbms_Lob.Getlength(p_Clob_Input)-35,Dbms_Lob.Substr(p_Clob_Input,Dbms_Lob.Getlength(p_Clob_Input)-2, 33));
END;
然后我尝试使用以下代码,它工作正常,但是,如果长度为 32001 或 64001,它仍然会失败,而且我觉得实现 objective 的代码太长了,
DECLARE
p_Clob_Index NUMBER;
p_Length NUMBER;
p_Chunk VARCHAR2(32000);
p_Clob_Input CLOB := ''; --> value more than 32K
p_Clob_Output CLOB; --> input CLOB value after removing first 33 characters and last 2 characters
BEGIN
Dbms_Lob.Createtemporary(p_Clob_Output, FALSE);
p_Length := Dbms_Lob.Getlength(p_Clob_Input);
p_Clob_Index := 1;
WHILE p_Clob_Index <= p_Length
LOOP
IF p_Clob_Index = 1
THEN
IF p_Length > 32000
THEN
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, 32000, 33);
ELSE
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, p_Length - 2, 33);
END IF;
ELSE
IF p_Clob_Index > p_Length - 32000
THEN
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, (p_Length - p_Clob_Index) - 1, p_Clob_Index);
ELSE
p_Chunk := Dbms_Lob.Substr(p_Clob_Input, 32000, p_Clob_Index);
END IF;
END IF;
IF p_Clob_Index > p_Length - 32000
THEN
p_Clob_Index := p_Length + 1;
ELSE
p_Clob_Index := p_Clob_Index + 32000;
END IF;
Dbms_Lob.Writeappend(p_Clob_Output, Length(p_Chunk), p_Chunk);
END LOOP;
END;
感谢您的支持
我的数据库版本是 11.2.0.4.0
谢谢...
您的第一个代码块因值较大而失败,因为 the second argument to writeappend()
是 varchar2
,因此限制为 32k(在 PL/SQL 上下文中,4k 来自 SQL) .
您可以改用 the copy
procedure,它有 CLOB 参数:
DBMS_LOB.COPY ( dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, src_lob IN CLOB CHARACTER SET dest_lob%CHARSET, amount IN INTEGER, dest_offset IN INTEGER := 1, src_offset IN INTEGER := 1);
所以你可以这样做:
dbms_lob.createtemporary(p_clob_output, false);
dbms_lob.copy(p_clob_output, p_clob_input, dbms_lob.getlength(p_clob_input) - 35, 1, 34);
您的变量名(以及您用“值超过 32K”暗示的赋值,这也不适用于大字面值)表明您可能正在努力执行此操作;你可以这样做:
create or replace procedure your_proc (
p_clob_input in clob,
p_clob_output out clob,
p_trim_start number,
p_trim_end number
) as
begin
dbms_lob.createtemporary(p_clob_output, false);
dbms_lob.copy(
dest_lob => p_clob_output,
src_lob => p_clob_input,
amount => dbms_lob.getlength(p_clob_input) - (p_trim_start + p_trim_end),
dest_offset => 1,
src_offset => p_trim_start + 1);
end;
/
虽然这是否真的会让您的生活比直接调用 dbms_lob
更轻松,但仍有争议。
只需使用 SUBSTR
,因为它适用于 CLOB
超过 32767 个字符的值:
DECLARE
p_Clob_Input CLOB := EMPTY_CLOB();
p_Clob_Output CLOB;
p_start_offset PLS_INTEGER := 33;
p_end_offset PLS_INTEGER := 2;
BEGIN
FOR i IN 1 .. 10 LOOP
p_clob_input := p_clob_input || LPAD('1234567890', 4000, '1234567890');
END LOOP;
p_clob_output := SUBSTR(
p_clob_input,
p_start_offset + 1,
LENGTH( p_clob_input ) - p_start_offset - p_end_offset
);
DBMS_OUTPUT.PUT_LINE( 'Lengths:' );
DBMS_OUTPUT.PUT_LINE( LENGTH( p_clob_input ) );
DBMS_OUTPUT.PUT_LINE( LENGTH( p_clob_output ) );
DBMS_OUTPUT.PUT_LINE( 'Starts:' );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_input, 1, 40 ) );
DBMS_OUTPUT.PUT_LINE( LPAD( ' ', p_start_offset, ' ' ) || SUBSTR( p_clob_output, 1, 40 - p_start_offset ) );
DBMS_OUTPUT.PUT_LINE( 'Ends:' );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_input, 39961 ) );
DBMS_OUTPUT.PUT_LINE( SUBSTR( p_clob_output, 39961 - p_start_offset ) );
END;
/
输出:
Lengths: 40000 39965 Starts: 1234567890123456789012345678901234567890 4567890 Ends: 1234567890123456789012345678901234567890 12345678901234567890123456789012345678
db<>fiddle here