Home » SQL & PL/SQL » SQL & PL/SQL » dbms_lob.substr (Oracle version 12.01, UNIX)
icon5.gif  dbms_lob.substr [message #595424] Wed, 11 September 2013 04:05 Go to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

I want to print data from a clob in XML format and use the following code:

PROCEDURE printClobOut(result IN OUT NOCOPY CLOB) is
xmlstr varchar2(32767);
line varchar2(32767);
cnt NUMBER;
leng NUMBER;


begin
xmlstr := dbms_lob.SUBSTR(result,32767);
leng := dbms_lob.getlength(result);

NHLS_UTILITIES.OUTPUT_log('XML length: ' || leng);

SELECT count(*)
INTO cnt
FROM xxnhls_pay_hours2;

NHLS_UTILITIES.OUTPUT_log('count lines: ' || cnt);

FOR i in 1..cnt LOOP
line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);

Fnd_File.PUT_LINE(Fnd_File.OUTPUT,line);;

xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
END LOOP;
end;

However the length of the clob is 13832630 which is too large for a VARCHAR2. Thus my output of line is cut off at 4000 characters. How can i increase this... Do i overlook something here in my code? Please help
Re: dbms_lob.substr [message #595426 is a reply to message #595424] Wed, 11 September 2013 04:11 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Welcome to the forum.

Please read OraFAQ Forum Guide and How to use [code] tags and make your code easier to read.
Make sure that lines of code do not exceed 80 characters when you format.
Indent the code, use code tags and align the columns in result.
Use the "Preview Message" or "Preview Quick Reply" button to verify.
Also always post your Oracle version, with 4 decimals.

Quote:
my output of line is cut off at 4000 characters.


A VARCHAR2 is limited to 32K-1 bytes in PL/SQL not to 4000 characters (as you can see in the declare you posted here).
Fix your procedure (we don't know) to enable it to handle more characters.
Also, you can use the standard SUBSTR function in your version, you don't need dmbms_lob package.

Regards
Michel
Re: dbms_lob.substr [message #595429 is a reply to message #595426] Wed, 11 September 2013 04:22 Go to previous messageGo to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

Hi Michel.

Thanks for the reply. This my question, I dont know how to fix. I have tried to declare the xmlstr variable as VARCHAR2, CLOB or NCLOB byt still ge the same results. The count of rows in the table is 22178 and could be larger it depends on the amont of months or employees.

Regards

Johann
Re: dbms_lob.substr [message #595435 is a reply to message #595424] Wed, 11 September 2013 04:52 Go to previous messageGo to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

PROCEDURE printClobOut(result IN OUT NOCOPY CLOB) is
xmlstr varchar2(32767);
line varchar2(32767);
cnt NUMBER;
leng NUMBER;


begin
    xmlstr := dbms_lob.SUBSTR(result,32767);
    leng := dbms_lob.getlength(result);

  NHLS_UTILITIES.OUTPUT_log('XML length: ' || leng);

  SELECT count(*)
  INTO cnt
  FROM xxnhls_pay_hours2;

  NHLS_UTILITIES.OUTPUT_log('count lines: ' || cnt);

  FOR i in 1..cnt LOOP
    line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);

    Fnd_File.PUT_LINE(Fnd_File.OUTPUT,line);;

    xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
  END LOOP;
end; 

Re: dbms_lob.substr [message #595441 is a reply to message #595435] Wed, 11 September 2013 05:08 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
The problem seems to NOT be in what you posted but in what you didn't: the procedures you call.
In fact, it is hard to tell where is the error if you don't post the execution of an example AND the code of all what you use.

Regards
Michel
Re: dbms_lob.substr [message #595460 is a reply to message #595441] Wed, 11 September 2013 06:16 Go to previous messageGo to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

Below the entire procedure


CREATE OR REPLACE PROCEDURE xxnhls_annual_element_values (errbuf OUT NOCOPY  VARCHAR2
                                                           ,retcode OUT NOCOPY  NUMBER
                                                           ,p_start_date DATE
                                                          , p_end_date DATE
                                                --          , p_element_type VARCHAR2
                                                         ) IS
/******************************************************************************
   name:       xxnhls_annual_element_values
   purpose:    xml output of all input values for a specific element over a period
   revisions:
   ver        date              author           description
   ---------  ----------  ---------------  ------------------------------------
   1.0        04/09/2013  Johann du Toit   initial creation 


   parameters:        p_start_date DATE
                      p_end_date DATE

   called by:       concurrent request


/* notes:
*******************************************************************************/     

gv_element_type_id NUMBER;
gv_run_result_id NUMBER;
gv_error NUMBER := 0;
element_entry NUMBER;
gv_input_cnt NUMBER :=0;
gv_assignment_number per_all_assignments_f.assignment_number%TYPE;
gv_emp_name per_all_people_f.first_name%TYPE;
gv_emp_last_name per_all_people_f.Last_name%TYPE;
gv_ccentre pay_cost_allocation_keyflex.segment3%TYPE;
gv_ccentre_desc FND_FLEX_VALUES_tl.description%TYPE;
gv_header VARCHAR2(32767) := 'x';
sqlstr VARCHAR2 (32767);
queryCtx dbms_xmlquery.ctxType;
result CLOB;
                                                            
CURSOR actions IS
SELECT /*+ INDEX_SS(PAA) */ paa.assignment_id, paa.assignment_action_id, date_earned
FROM pay_assignment_actions paa
     , pay_payroll_actions ppa
WHERE paa.payroll_action_id = ppa.payroll_action_id     
AND action_type = 'R' -- run
AND ppa.ACTION_STATUS = 'C' --completed
and paa.run_type_id = 62
--and assignment_id = 149
AND effective_date between p_start_date and p_end_date
order by assignment_id;

CURSOR element_values (p_assignment_id NUMBER,p_element_id NUMBER, p_element_entry_id NUMBER,  p_date DATE)  IS 
SELECT pivf.name, PEEVF.SCREEN_ENTRY_VALUE
FROM  pay_element_entries_f peef
      , PAY_ELEMENT_ENTRY_VALUES_F peevf
      , pay_input_values_f pivf
WHERE assignment_id = p_assignment_id
AND peef.element_type_id = p_element_id
AND PEEVF.INPUT_VALUE_ID = PIVF.INPUT_VALUE_ID
AND PEEF.ELEMENT_ENTRY_ID = PEEVF.ELEMENT_ENTRY_ID
and peef.element_entry_id = p_element_entry_id
AND p_date between PEEF.EFFECTIVE_START_DATE and PEEF.EFFECTIVE_END_DATE
AND p_date between PEEvF.EFFECTIVE_START_DATE and PEEvF.EFFECTIVE_END_DATE
AND p_date between Pivf.EFFECTIVE_START_DATE and PivF.EFFECTIVE_END_DATE
order by PEEVF.INPUT_VALUE_ID  ;


CURSOR col IS
SELECT LOWER(COLUMN_NAME) column_name, column_id
FROM SYS.DBA_TAB_COLUMNS
WHERE owner = UPPER('Apps')
AND table_name = UPPER('xxnhls_pay_hours2')
ORDER BY column_id;

PROCEDURE printClobOut(result IN OUT NOCOPY CLOB) is
xmlstr long; --varchar2(32767);
line varchar2(32767);
cnt NUMBER;
leng NUMBER;


begin
    xmlstr := dbms_lob.SUBSTR(result,32767);
    leng := dbms_lob.getlength(result);
    
    NHLS_UTILITIES.OUTPUT_log('XML length: ' || leng);
  --  NHLS_UTILITIES.OUTPUT_log('XML string 1: ' || xmlstr);
    
    SELECT count(*) 
    INTO cnt
    FROM xxnhls_pay_hours2;
    
    NHLS_UTILITIES.OUTPUT_log('count lines: ' || cnt);
    
    FOR i in 1..cnt LOOP
      line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);
        
        NHLS_UTILITIES.OUTPUT_OUT(line);
      --   dbms_output.put_line(line);
       
        xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
    END LOOP;
    /*
    
    loop
    exit when xmlstr is null;
    
        line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);
        
      --   Fnd_File.PUT_LINE(Fnd_File.OUTPUT,line);
      --   dbms_output.put_line(line);
       
        xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
        
    end loop; */
end;            
PROCEDURE pivot_data IS

BEGIN
   NHLS_UTILITIES.OUTPUT_LOG ('Pivot data');
  --Drop table
  BEGIN 
   NHLS_UTILITIES.OUTPUT_log('Drop pivot table');
   
    EXECUTE IMMEDIATE 'drop table xxnhls_pay_hours2';
    
  EXCEPTION
   WHEN OTHERS THEN
     NHLS_UTILITIES.OUTPUT_log('Error dropping table:' || SQLERRM);
  END;  
  
  -- Create Table
  BEGIN
  
    NHLS_UTILITIES.OUTPUT_log('Create pivot table');
    execute immediate 'CREATE table xxnhls_pay_hours2  as (select *  from table( pivot(  ''select * from xxnhls_pay_hours'' ) ))';
    
  EXCEPTION
    WHEN OTHERS THEN
      NHLS_UTILITIES.OUTPUT_log('Error creating pivot table: ' || SQLERRM);
  END;
  
EXCEPTION
  WHEN OTHERS THEN
    NHLS_UTILITIES.OUTPUT_log('Error in pivot:' || SQLERRM);
    IF SQLCODE = -942 THEN
      NHLS_UTILITIES.OUTPUT_log('the table did not exist!');
    END IF;
    
END;



BEGIN
    SELECT element_type_id
    INTO gv_element_type_id
    FROM pay_element_types_f
    WHERE element_name = 'NHLS Hours Input' ;
    --p_element_type;
    NHLS_UTILITIES.OUTPUT_LOG ('Element_type_id: ' || gv_element_type_id);
    


DELETE FROM xxnhls_pay_hours;
 
    
    FOR ass in actions LOOP

           BEGIN 
            SELECT run_result_id , ELEMENT_ENTRY_ID
            INTO gv_run_result_id, element_entry
            FROM pay_run_results
            where element_type_id = gv_element_type_id
            AND assignment_action_id = ass.assignment_action_id;
           
           EXCEPTION
             WHEN OTHERS THEN 
               gv_error := 1; 
           END; 
         
     IF gv_error  = 0 THEN  
     
      BEGIN 
      
            SELECT /*+ INDEX_DESC(PAAF) */ assignment_number
                   , first_name
                   , last_name
                   , NHLS_UTILITIES.GET_EMPLOYEE_CCENTRE(paaf.assignment_id,ass.date_earned)ccentre
            INTO gv_assignment_number
                 , gv_emp_name
                 , gv_emp_last_name
                 , gv_ccentre         
            FROM per_all_assignments_f paaf
                 , per_all_people_f papf
            WHERE assignment_id = ass.assignment_id
            AND paaf.person_id = papf.person_id
            AND ass.date_earned between papf.effective_start_date and papf.effective_end_date
            AND ass.date_earned between paaf.effective_start_date and paaf.effective_end_date;
                        
            gv_ccentre_desc := NHLS_UTILITIES.GET_EMPLOYEE_CCENTRE_DESC(gv_ccentre);
            

                
           -- NHLS_UTILITIES.OUTPUT_LOG ('..Assignment_id: ' || ass.assignment_id);
           -- NHLS_UTILITIES.OUTPUT_LOG ('..Date_earned: ' || ass.date_earned);
          --  NHLS_UTILITIES.OUTPUT_LOG ('..Element Entry ID: ' || element_entry);
          --  NHLS_UTILITIES.OUTPUT_LOG ('..Assignment_action_id: ' || ass.Assignment_action_id);
            
            gv_input_cnt := 1;
            
              FOR va IN element_values (ass.assignment_id, gv_element_type_id, element_entry, ass.date_earned) LOOP
               
                INSERT INTO xxnhls_pay_hours values (gv_assignment_number
                                                    ,  gv_emp_name
                                                     , gv_emp_last_name
                                                     , gv_ccentre   
                                                     , gv_ccentre_desc
                                                     , to_char(ass.date_earned, 'MON-YY')
                                                     , replace(va.name,' ','_')
                                                     , nvl(va.SCREEN_ENTRY_VALUE,0));      
                
               commit; 
              END LOOP;
                 

            END;
    
     END IF;
     
       gv_error := 0;
       
    END LOOP;
   
-- Output


  pivot_data; 
  
  for a IN col LOOP
    gv_header := replace(a.column_name,' ','_') || ',' || gv_header ;
   
  END LOOP;
  

   gv_header := substr(gv_header,1, length(gv_header)-2);
   
   NHLS_UTILITIES.OUTPUT_LOG('Header:' || gv_header);
   
  sqlstr := 'SELECT ' || gv_header ||' FROM apps.xxnhls_pay_hours2';
  
 NHLS_UTILITIES.OUTPUT_LOG(sqlstr); 
  
  queryCtx := dbms_xmlquery.newContext(sqlstr);
 
    dbms_xmlquery.setRowTag(
          queryCtx
        , 'EMP'
      );
      dbms_xmlquery.setRowSetTag(
          queryCtx
        , 'EMPSET'
      );         
      
  result := dbms_xmlquery.getXml(queryCtx);
  printClobOut(result);
  dbms_xmlquery.closeContext(queryCtx);                                    
  

  
END;


Re: dbms_lob.substr [message #595472 is a reply to message #595460] Wed, 11 September 2013 06:35 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Sorry I was not clear, in your example, we have not the code for "Fnd_File.PUT_LINE" and I think the error comes from this procedure.

Now for the code you posted, every WHEN OTHERS should at least end with a "RAISE;" statement (if it actually does something) and most often just be removed.

Regards
Michel
Re: dbms_lob.substr [message #595494 is a reply to message #595472] Wed, 11 September 2013 07:14 Go to previous messageGo to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

Hi Michel

It seems like I will not get any help here. Thanks for nothing.

The error is NOT from the "Fnd_File.PUT_LINE" as this procedure is used extensively in ALL my reports and I had not got any problems this far. Secondly my problem is NOT in the exception, and thisa is the way I want to handle the exception and NOT raise any errors.

Regards

JOHANN
Re: dbms_lob.substr [message #595519 is a reply to message #595494] Wed, 11 September 2013 08:36 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Quote:
The error is NOT from the "Fnd_File.PUT_LINE" as this procedure is used extensively in ALL my reports and I had not got any problems


Even with line longer than 4000?

Quote:
Secondly my problem is NOT in the exception, and thisa is the way I want to handle the exception and NOT raise any errors.


It was just an advice, I bet 1 million bucks you WILL have a problem due to this.

In your example, if you remove all what is not necessary for the issue you have:
PROCEDURE printClobOut(result IN OUT NOCOPY CLOB) is
xmlstr varchar2(32767);
line varchar2(32767);
cnt NUMBER;

begin
  xmlstr := dbms_lob.SUBSTR(result,32767);

  SELECT count(*)
  INTO cnt
  FROM xxnhls_pay_hours2;

  FOR i in 1..cnt LOOP
    line := substr(xmlstr,1,instr(xmlstr,chr(10))-1);
    Fnd_File.PUT_LINE(Fnd_File.OUTPUT,line);;
    xmlstr := substr(xmlstr,instr(xmlstr,chr(10))+1);
  END LOOP;

end; 

So what is relation between the number of lines you put_line and the input data (result)?
Any string you pass in input to the procedure you will put_line the SAME number of lines: the number of rows in the "xxnhls_pay_hours2" table.
This is quite strange for me.
If you want to put_line more lines and go after the 32K, you must not copy the input string into a VARCHAR2 variable and not shrink the variable (here xmlstring) each time you put a line but use a pointer to go from one NL to the next one.

Regards
Michel

[Updated on: Wed, 11 September 2013 08:37]

Report message to a moderator

Re: dbms_lob.substr [message #595541 is a reply to message #595494] Wed, 11 September 2013 10:28 Go to previous messageGo to next message
realspirituals
Messages: 27
Registered: September 2011
Location: Italy
Junior Member

johanndut wrote on Wed, 11 September 2013 07:14
It seems like I will not get any help here. Thanks for nothing.

Be Polite. People are trying to help you and that is the reason you get replies.
Re: dbms_lob.substr [message #595584 is a reply to message #595519] Thu, 12 September 2013 01:20 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Received on PM:

johanndut wrote on Thu, 12 September 2013 08:02
Hi Michel

Attached is the output of that script. You will see it just stop at one point... I really don't know what to do there are more employees to follow but they are gone...

Please I a desperate for some help here.

Thanks

JOHANN


So you have the expected behaviour:
1/ The number of lines is the number of your rows (22179).
2/ You have the first 32K of data as you copy the first 32K of your clob ("result") into a varchar2(32767) variable ("xmlstr")

I told you what to do:

Quote:
If you want to put_line more lines and go after the 32K, you must not copy the input string into a VARCHAR2 variable and not shrink the variable (here xmlstring) each time you put a line but use a pointer to go from one NL to the next one.


Regards
Michel

Re: dbms_lob.substr [message #595585 is a reply to message #595584] Thu, 12 September 2013 01:23 Go to previous messageGo to next message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

Yes I saw the posting... I am not familiar with this. I am not familiar with working with LOB's at all. You state I need to use a pointer...how is that done?

Regards
Re: dbms_lob.substr [message #595588 is a reply to message #595585] Thu, 12 September 2013 01:57 Go to previous messageGo to next message
Michel Cadot
Messages: 68770
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
A "pointer" is just an integer giving the character you are working on, like the "instr(xmlstr,chr(10))" you used which is a pointer to the next NL.
Here an example (separator is not new_line but | for this example):
SQL> declare
  2    result varchar2(100) := 'this|is|an|example|';
  3    l pls_integer := length(result);
  4    i pls_integer := 1;
  5    j pls_integer;
  6    k pls_integer := 1;
  7  begin
  8    while k <= l loop
  9      j := instr(result, '|', 1, i);
 10      dbms_output.put_line(substr(result, k, j-k));
 11      k := j + 1;
 12      i := i + 1;
 13    end loop;
 14  end;
 15  /
this
is
an
example

PL/SQL procedure successfully completed.

Regards
Michel
Re: dbms_lob.substr [message #595590 is a reply to message #595588] Thu, 12 September 2013 02:10 Go to previous message
johanndut
Messages: 8
Registered: September 2013
Location: Johannesburg
Junior Member

Hi Michel.

Thanks for this. I will try and let you know.

Great

JOHANN
Previous Topic: insert select in PLSQL
Next Topic: Date In Ascending Order
Goto Forum:
  


Current Time: Sat Sep 06 18:13:14 CDT 2025