Skip to Main Content
  • Questions
  • How to fetch up to 5MB of text/string/data from a larger a clob in oracle

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, learning.

Asked: February 20, 2017 - 10:21 am UTC

Last updated: February 21, 2017 - 10:37 am UTC

Version: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

Viewed 10K+ times! This question is

You Asked

Hi Oracle,
 CREATE TABLE XMLISSUE
                ( 
                  xmltablecolumn clob
                 
                );

Created a table

As shown below code I have inserted some data to clob
DECLARE 
 XMLCLOB clob;

BEGIN
 
   SELECT  XMLTYPE(
                   DBMS_XMLGEN.GETXML(q'{SELECT * FROM   whse_detail e WHERE  ROWNUM <= 10000 }')
                  ).getclobval()   as data1  INTO XMLCLOB 
          FROM   DUAL; 
          
         -- SELECT XMLCLOB FROM DUAL;
        --  DBMS_OUTPUT.PUT_LINE(XMLCLOB);
        INSERT INTO XMLISSUE(XMLTABLECOLUMN) VALUES(XMLCLOB);
          
 -- SELECT LENGTHB(XMLTABLECOLUMN) AS AASDF
--FROM XMLISSUE;
 
END;

 SELECT XMLTABLECOLUMN AS xmlclob
FROM XMLISSUE;


XMLISSUE is my table having clob type column.That column is having more than 10 MB text/data.
I need to fetch less than 5MB data from that clob.
How can I do it..??

Thank you in advance..

and Chris said...

You can use functions in DBMS_LOB to find the length of a clob and substring it:

drop table t purge;
create table t (
  x clob
);

declare
  tmp clob;
  str varchar2(32767) := lpad('x', 32767, 'x');
begin
  dbms_lob.createtemporary(tmp,true);
  
  for i in 1 .. 200 loop
    dbms_lob.writeappend(tmp,length(str),str);
  end loop;
  
  insert into t values (tmp);
end;
/

select dbms_lob.getlength(x) from t;

DBMS_LOB.GETLENGTH(X)  
6,553,400  

select dbms_lob.getlength(dbms_lob.substr(x, 4000, 1)) from t;

DBMS_LOB.GETLENGTH(DBMS_LOB.SUBSTR(X,4000,1))  
4,000  


http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_lob.htm#ARPLS600

But there's a problem with this approach. Dbms_lob.substr returns a varchar2. In SQL the maximum length of this is 4,000 bytes*. So if you attempt to return strings longer than this you get an error:

select dbms_lob.substr(x, 4001, 1) from t;

SQL Error: ORA-06502: PL/SQL: numeric or value error: character string buffer too small


The limit of varchar2 in PL/SQL is 32k. So you can extract larger strings, but still not the 5Mb you're looking for:

declare
  subs varchar2(32767);
  tclob clob;
begin
  select x
  into   tclob
  from   t;
  
  subs := dbms_lob.substr(tclob, 32767, 1);
      
  dbms_output.put_line('Clob length: ' || dbms_lob.getlength(subs));
end;
/

PL/SQL procedure successfully completed.
Clob length: 32767

declare
  subs  clob;
  tclob clob;
begin
  select x
  into   tclob
  from   t;

  subs := dbms_lob.substr(tclob, 32768, 1);
      
  dbms_output.put_line('Clob length: ' || dbms_lob.getlength(subs));
end;
/

PL/SQL procedure successfully completed.
Clob length:


So how to get around this?

Make repeated calls to dbms_lob.substr in PL/SQL!

declare
  len   pls_integer;
  tclob clob;
  subc  clob;
begin

  select x
  into   tclob
  from   t;
  
  for i in 0 .. 99 loop
    subc := subc || dbms_lob.substr(tclob, 32767, (32767*i) +1);
  end loop;
  
  dbms_output.put_line('Clob length: ' || dbms_lob.getlength(subc));
end;
/

PL/SQL procedure successfully completed.
Clob length: 3276700


Note: When processing clobs, the functions work on the number of characters. This is fine if you're sure the strings only use single byte characters. But if your text can contain multi-byte characters, fetching the substring of 5*1024^2 could exceed 5Mb. If 5Mb is a hard limit you could convert the clob to a blob. Then substr works on number of bytes. Be aware: if the last character is multi-byte, it may incorrectly chop it into two!

*In 12.1 this is increased to 32,767 if you're using extended data types.

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

dbms_lob.copy?

anton, February 20, 2017 - 2:23 pm UTC

What's wrong with using dbms_lob.copy instead of looping dbms_lob.substr.

Or using using xml functinonality, like xmltype( xmlclob ).extract( <xpath> ).getclobval()
Chris Saxon
February 21, 2017 - 10:37 am UTC

Great suggestion: dbms_lob.copy would work too!

Doing an XML extract relies on you knowing that the path you're getting will always be small enough.

I am requesting for a script to fetch less than 5mb not size/length, but data/text

learning begineer, February 22, 2017 - 12:56 pm UTC

Dear Chris Saxon,
Thank you for your replay.
Actually I got till finding the size/length of XML Clob.
But,I want the text/data/sometext of xml clob, so that it should be <5MB.

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here