当前位置: 首页 > 知识库问答 >
问题:

如何克服substr和clob限制?

郦祯
2023-03-14

我有一个XML存储在CLOB中。为了显示来自XML的特定数据,我需要运行各种substr和instr函数。

我当前的代码使用varchar2(32000)变量处理它,如下所示:

select xml_data into xmlclob
                 from test.test_data_v6 
                 where test_id =r1.test_id;

                 start_position := dbms_lob.instr(xmlclob,'<DataSheet>',1,1)+11;
                 end_position := dbms_lob.instr(xmlclob,'</DataSheet>',start_position,1);                         
                 l_str := (dbms_lob.substr(xmlclob, end_position - start_position, start_position));                   
                 l_str := substr(l_str, instr(l_str, '<SummaryParameters>'),instr(l_str, '</SummaryParameters>')-instr(l_str, '<SummaryParameters>')+20);
select xml_data into xmlclob
                 from test.test_data_v6_temp 
                 where test_id =r1.test_id;

                 start_position := dbms_lob.instr(xmlclob,'<DataSheet>',1,1)+11;
                 end_position := dbms_lob.instr(xmlclob,'</DataSheet>',start_position,1);                         
                 l_str := dbms_lob.substr(xmlclob, end_position - start_position, start_position);
                 l_str1 := substr(l_str, instr(l_str, '<SummaryParameters>'), instr(l_str, '</SummaryParameters>')-instr(l_str, '<SummaryParameters>')+20);

我编写了一个匿名块来测试子字符串的限制,如下所示:

declare
error_reason varchar2(32000);
start_position number;
end_position number;
str_length number;
str_length2 number;
l_clob2 clob;
l_str varchar2(32000);
e_clob clob;
temp_clob clob;
begin
           select xml_data into l_clob2 from test.test_data_v6_temp where test_id=(hard coded the test id);

           start_position := dbms_lob.instr(l_clob2,'<DataSheet>',1,1)+11;
           dbms_output.put_line('startposition='||start_position);
           end_position := dbms_lob.instr(l_clob2,'</DataSheet>',start_position,1);
           dbms_output.put_line('end position='||end_position);
           str_length := end_position-start_position;
           str_length2 := 30000;
           dbms_output.put_line('str_length='||str_length);
           dbms_output.put_line('str_length2='||str_length2);
           dbms_output.put_line('str_length='||str_length);

                        temp_clob := dbms_lob.substr(l_clob2, str_length2, start_position);
                   --dbms_output.put_line('temp_clob1='||temp_clob);
                  --temp_clob := substr(temp_clob, instr(temp_clob, '<SummaryParameters>'), instr(temp_clob, '</SummaryParameters>')-instr(temp_clob, '<SummaryParameters>')+20);
                  insert into test.temp values(temp_clob);
                 commit;

end;

--select * from test.temp

我注释掉了第二个子字符串,只是为了看看如果我将str_length更改为32000以下,表是否会填充数据,并且它确实被填充了。

这是我的输出

startposition=202134
end position=237746
str_length=35612
str_length2=30000
declare
start_position number;
end_position number;
str_length number;
str_length2 number;
sp2 number;
ep2 number;
str_len number;
 str_len2 number;
 l_clob2 clob;
temp_clob clob;
temp_clob2 clob;
 begin
               select xml_data into l_clob2 from test.test_data_v6_temp where test_id=211230309;

             start_position := dbms_lob.instr(l_clob2,'<DataSheet>',1,1)+11;
            dbms_output.put_line('startposition='||start_position);
           end_position := dbms_lob.instr(l_clob2,'</DataSheet>',start_position,1);
               dbms_output.put_line('end position='||end_position);
               str_length := end_position-start_position;

            dbms_output.put_line('Original clob size: ' || dbms_lob.getlength(l_clob2));
            dbms_lob.createtemporary(temp_clob, false);
            while str_length > 0 
            loop
            str_length2 := least(str_length, 32768);
            str_length := str_length - str_length2;
            dbms_lob.copy(temp_clob, l_clob2, str_length2,dbms_lob.getlength(temp_clob) + 1, start_position);
            start_position := start_position + str_length;
              end loop;
             dbms_output.put_line('Copied clob 1 size: ' || dbms_lob.getlength(temp_clob));
             sp2 := dbms_lob.instr(temp_clob,'<SummaryParameters>')+20;
                dbms_output.put_line('sp2 = '|| sp2);
              ep2 := instr(temp_clob, '</SummaryParameters>');
                dbms_output.put_line('ep2 = '|| ep2);

              str_len :=ep2 - sp2;
              dbms_lob.createtemporary(temp_clob2, false);
             while str_len > 0 
              loop
                str_len2 := least(str_len, 32768);
                str_len := str_len - str_len2;
                dbms_lob.copy(temp_clob2, temp_clob, str_len2,dbms_lob.getlength(temp_clob2) + 1, sp2);
                sp2 := sp2 + str_len;
              end loop; 


            dbms_output.put_line('Copied 2 clob size: ' || dbms_lob.getlength(temp_clob2));

 insert into test.temp values(temp_clob2);
                  commit;
end;

下面是我的输出:

startposition=202134
end position=237746
Original clob size: 1723831
Copied clob 1 size: 35612
sp2 = 703
ep2 = 0
Copied 2 clob size: 0

共有1个答案

衡安晏
2023-03-14

下面是一个使用copy过程避免切换到varchar2的示例:

   dbms_output.put_line('Original clob size: ' || dbms_lob.getlength(l_clob2));
   dbms_lob.createtemporary(temp_clob, false);
   while str_length > 0 loop
     str_length2 := least(str_length, 32768);
     str_length := str_length - str_length2;
     dbms_lob.copy(temp_clob, l_clob2, str_length2,
       dbms_lob.getlength(temp_clob) + 1, start_position);
     start_position := start_position + str_length2;
   end loop;
   dbms_output.put_line('Copied clob size: ' || dbms_lob.getlength(temp_clob));

使用我填充的'xml'值,它给出了输出:

startposition=17
end position=40456
str_length=40439
str_length2=30000
str_length=40439
Original clob size: 40473
Copied clob size: 40439

因此temp_clob包含原始CLOB的40K+“子字符串”。

您可以通过使用以下内容从XML中提取相关数据来避免这项工作:

select xmlquery('*/DataSheet/SummaryParameters/*'
  passing xmltype(xml_data) returning content))
from ...

或在旧版本中(在11GR2中不推荐):

select extract(xmltype(xml_data), '*/DataSheet/SummaryParameters/*')
from ...

其中任何一个都将为您提供 ... 中的部分。从您的问题中看不出datasheet是顶部元素,还是summaryparameters直接位于该元素内部,因此您可能需要尝试将通配符放在哪里。有关XMLQuery的更多信息请参见文档。

declare
  start_position number;
  end_position number;
  str_length number;
  str_length2 number;
  l_clob2 clob;
  temp_clob clob;
  temp_clob2 clob;
begin
  select xml_data into l_clob2 from t42 where id = 1;

  start_position := dbms_lob.instr(l_clob2,'<DataSheet>',1,1)+11;
  dbms_output.put_line('startposition='||start_position);
  end_position := dbms_lob.instr(l_clob2,'</DataSheet>',start_position,1);
  dbms_output.put_line('end position='||end_position);
  str_length := end_position-start_position;

  dbms_lob.createtemporary(temp_clob, false);
  while str_length > 0 loop
    str_length2 := least(str_length, 32768);
    str_length := str_length - str_length2;
    dbms_lob.copy(temp_clob, l_clob2, str_length2,
      dbms_lob.getlength(temp_clob) + 1, start_position);
    start_position := start_position + str_length2;
  end loop;
  dbms_output.put_line('temp_clob length: ' || dbms_lob.getlength(temp_clob));

  start_position := dbms_lob.instr(temp_clob,'<SummaryParameters>',1,1)+19;
  dbms_output.put_line('startposition='||start_position);
  end_position := dbms_lob.instr(temp_clob,'</SummaryParameters>',start_position,1);
  dbms_output.put_line('end position='||end_position);
  str_length := end_position-start_position;

  dbms_lob.createtemporary(temp_clob2, false);
  while str_length > 0 loop
    str_length2 := least(str_length, 32768);
    str_length := str_length - str_length2;
    dbms_lob.copy(temp_clob2, temp_clob, str_length2,
      dbms_lob.getlength(temp_clob2) + 1, start_position);
    start_position := start_position + str_length2;
  end loop;
  dbms_output.put_line('temp_clob2 length: ' || dbms_lob.getlength(temp_clob2));

  insert into t42 values (2, temp_clob2);
end;
/

给出(用我编造的数据):

startposition=17
end position=40456
temp_clob length: 40439
startposition=220
end position=420
temp_clob2 length: 200
 类似资料:
  • 我正在使用spark 2.4.2读取包含600条记录的csv。最后100条记录有大量数据。我遇到的问题是, 我已经增加了到2g(最大允许设置)和火花驱动程序内存到1g,能够处理更多的记录,但仍然不能处理csv中的所有记录。 我试着翻页600条记录。e、 对于6个分区,我可以在每个分区处理100条记录,但由于最后100条记录太多,因此会发生缓冲区溢出。 在这种情况下,最后100条记录很大,但这可能是

  • 我有一个PL/SQL过程,它对参数执行大量s。我想删除长度限制,所以尝试将其更改为。 工作正常,但性能受到影响,所以我做了一些测试(基于2005年的这些测试)。 更新:我可以用不同的Oracle版本和不同的硬件在几个不同的实例上重现这个过程,总是明显比慢,而且比慢得多。 Bob的结果和上面链接中的测试讲述了一个不同的故事。 有人能解释这一点吗,或者至少重现鲍勃或我的结果吗?谢了! 测试结果:

  • 问题内容: 我知道XHTML不支持嵌套的表单标记,但是我仍然没有找到解决该问题的优雅方法。 有人说您不需要它,并且他们无法想到是否需要这样做。嗯,我个人不认为一个场景,我的 没有 需要它。 让我们看一个非常简单的例子: 您正在制作一个博客应用程序,您有一个表单,其中包含一些用于创建新帖子的字段以及一个带有“操作”(如“保存”,“删除”,“取消”)的工具栏。 我们的目标是以 不需要JavaScrip

  • 问题内容: 我正在使用扫描仪的方法读取文本文件行。但是,当我在文件行中达到一定大小时,扫描仪不再允许我读取它,而是返回一个空行。 我应该如何配置缓冲区以接收大量数据? 只是一个文件,行中有许多整数,并用空格分隔。例如,一行中有40000个整数。(请注意,它适用于小于或等于10000整数的文件行,但不适用于40000) 234 544 765 45 34 67 67 87 98 43 [… n =

  • 刚刚开始使用scala和spark来运行这个简单的程序:

  • 我有一个向CLOB追加字符串的场景。我遇到的问题是,一旦CLOB达到一定大小,如果我试图向CLOB追加更多内容,就会出现ORA-06502:PL/SQL:numeric或value错误。我假设它的大小已经用完了,但我不知道如何克服这个问题(即指定如何使clob变大)。 有人能帮帮我吗。 我就是这样宣布我的衣服的... 然后我像这样插入它.... 谢谢