generation_xml_plsql

16
Page 1 of 16 Generating XML Output for a PL/SQL Procedure This document gives us an idea about generating XML output from a sample PL/SQL Procedure. Wehavetookanexampleprocedure‘Schedule_a’ whichgivesthedetailsof dealers present for a contract and the details of the products that are associated with them. Procedure Schedule_a has got seven cursors in it, out of which, first cursor retrieves the details of dealers and the remaining ones get the details of the products that a dealer has got. Each cursor retrieves the details of a particular category of products. So each of the loops associated with these cursors are terminating ones inside the loop, which retrieves dealer details. This Procedure also takes certain input parameters like Fiscal Year, Division, region, Sales Reps, Customer Name basing on which we will be retrieving the dealer names. Now that we know the output variables given out by the procedure, we will create a table with the columns, which can hold the values of the output variables. We need to create a table dynamically to eliminate the problem of existence of the table basing on the instance at which we run our procedure. Xml output is generated using a built-in package ‘DBMS_XMLGEN.GETXML’ which takes a single select query as an input and generates XML output for the data given out by the query. Modifications made to the procedure are: 1. Added code to create a table at run-time. 2. Code has been added in each of the inner loops to insert the details of the products into the table that we have created. 3. At the end of the main loop, we will call the built-inpackage ‘dbms_xmlgen.getxml’ by passing the select query, which retrieves the data from the table that we have created. The output of this is stored into a variable whose data type is CLOB.

Upload: tiagovanderlei

Post on 27-Apr-2015

88 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Generation_XML_PLSQL

Page 1 of 16

Generating XML Output for a PL/SQL Procedure

This document gives us an idea about generating XML output from a sample

PL/SQL Procedure.

We have took an example procedure ‘Schedule_a’ which gives the details of

dealers present for a contract and the details of the products that are associated with them.

Procedure Schedule_a has got seven cursors in it, out of which, first cursor

retrieves the details of dealers and the remaining ones get the details of the products that a

dealer has got. Each cursor retrieves the details of a particular category of products. So each

of the loops associated with these cursors are terminating ones inside the loop, which

retrieves dealer details.

This Procedure also takes certain input parameters like Fiscal Year, Division,

region, Sales Reps, Customer Name basing on which we will be retrieving the dealer names.

Now that we know the output variables given out by the procedure, we will create a table

with the columns, which can hold the values of the output variables. We need to create a

table dynamically to eliminate the problem of existence of the table basing on the instance at

which we run our procedure.

Xml output is generated using a built-in package ‘DBMS_XMLGEN.GETXML’

which takes a single select query as an input and generates XML output for the data given

out by the query.

Modifications made to the procedure are:

1. Added code to create a table at run-time.

2. Code has been added in each of the inner loops to insert the details of the products into

the table that we have created.

3. At the end of the main loop, we will call the built-in package ‘dbms_xmlgen.getxml’ by

passing the select query, which retrieves the data from the table that we have created. The

output of this is stored into a variable whose data type is CLOB.

Page 2: Generation_XML_PLSQL

Page 2 of 16

4. We will also include code, which is required to retrieve the data from a CLOB variable.

We need to use another built-in package ‘DBMS_LOB.getLength’for this.

5. After we get the output and write it to an fnd_file, we will drop the table that we have

created.

Creating table dynamically:

Code associated with creating a table at run time uses EXECUTE IMMEDIATE

command.

Sample code for creating a table in this way is:

EXECUTE IMMEDIATE ('CREATE TABLE TEST_XML

(DEALER_ID VARCHAR2(2000),

DEALER_NAME VARCHAR2(240),

FISCAL_YEAR VARCHAR2(2000),

PRODUCT_NAME VARCHAR2(2000),

PRODUCT_DESCRIPTION VARCHAR2(2000))' );

Inserting data into the table created at run time:

In order to insert data into the table created at run time, we need to declare a variable

first and then use EXECUTE IMMEDIATE to populate the table with the required data.

Sample code for this is:

CREATE OR REPLACE PROCEDURE XML_PROC AS

stmt VARCHAR2 (200);

lv_val NUMBER := 10;

lv_val1 NUMBER := 20;

BEGIN

EXECUTE IMMEDIATE ('create table TEST_XML (x number,z number)');

stmt := 'insert into TEST_XML values(:1,:2)';

EXECUTE IMMEDIATE stmt USING lv_val, lv_val1;

END;

This code results in insertion of data from a dynamically created table using an

intermediate variable ‘stmt; which has the command to be executed in it. Here the :1,:2

represent temporary variables into which we will be passing the values of our variables

Page 3: Generation_XML_PLSQL

Page 3 of 16

‘lv_1’ and ‘lv_2’ using Execute Immediate command. After we have executed this piece of

code, we can see that the table y1 will be getting populated with a row of data.

Generating XML output using DBMS_XMLGEN.GETXML:

Now that we have created the table and inserted data into it, we can generate XML

output for the data present in this table using this built-in package. In order that we view the

XML output given out by this we need to declare a variable of CLOB type which could store

large amount of data. Sample code associated with the usage of this code is:

DECLARE

lv_1 CLOB;

BEGIN

SELECT DBMS_XMLGEN.getxml ('SELECT * FROM TEST_XML ') INTO lv_1 FROM DUAL;

END;

Retrieving data from a CLOB variable:

To retrieve data from a CLOB variable we need to declare four variables:

1. len : which calculates the length of the CLOB variable using

DBMS_LOB.getLength(<variable name>).

2. xmlstr : which is used to store the xml output of size 32767 bytes each time when it is in

the loop.

3. offset : which is a variable initialized to 32767 to restrict the amount of output fetched to

32767 for each loop.

4. retrieved: this variable is initialized to zero while declaring it and is incremented by a

value of 32767 each time it displays the output. This variable will hold the value of ‘len’ at

the end of the loop.

The following code gives a clear idea as of the usage of variables mention above:

CREATE OR REPLACE PROCEDURE USER_TEST_XML (

errbuf OUT VARCHAR2,

retcode OUT VARCHAR2 ) IS

lv_1 CLOB;

len NUMBER (10);

xmlstr VARCHAR2 (32767);

Page 4: Generation_XML_PLSQL

Page 4 of 16

offset NUMBER (10) := 32767;

retrieved NUMBER (10) := 0;

BEGIN

SELECT DBMS_XMLGEN.getxml ('SELECT * FROM TEST_XML') INTO lv_1 FROM DUAL;

len := DBMS_LOB.getlength (lv_1);

LOOP EXIT WHEN len = retrieved;

IF (len - retrieved) < 32767 THEN

SELECT SUBSTR (lv_1, retrieved + 1) INTO xmlstr FROM DUAL;

retrieved := len;

fnd_file.put_line (fnd_file.output, xmlstr);

ELSE

SELECT SUBSTR (lv_1, retrieved + 1, offset) INTO xmlstr FROM DUAL;

retrieved := retrieved + offset;

fnd_file.put_line (fnd_file.output, xmlstr);

END IF;

END LOOP;

END;

In this procedure after declaring the variables we will start the begin block which will

first retrieve the XML output into a clob variable lv_1.After the select statement, we have got

the length of the clob variable.

We have included a loop there, which will end when the retrieved data is equal to the

length of the data.

An IF-THEN-ELSE statement is also included inside the loop. In the IF condition we

will check when the length of the data is less than 32767 bytes and if it is so, we will print the

output into fnd_file and will equate the retrieved value to the len value.

If the condition is not satisfied, the execution will now navigate to ELSE part and will

select the first 32767 bytes of data. The Else part also increments the value of the variable

‘retrieved’ by 32767. Now, we will print it into the fnd_file and will enter into the second

loop now. Again, it will check for the length and prints the value into fnd_file. This loop will

end when all the data is displayed.

Page 5: Generation_XML_PLSQL

Page 5 of 16

Dropping the dynamic table that we have created:

As we have got all the output that we need to display into the fnd_file, we can now

drop the table that we have created using EXECUTE IMMEDIATE. Sample code to drop a

table created at run-time is as follows:

EXECUTE IMMEDIATE ('drop table TEST_XML ');

Now , if we run the concurrent program which uses the procedure that we have modified,

we will get the required XML output.

Sample Procedure to get XML from a PL/SQL procedure:

CREATE OR REPLACE PROCEDURE user_riso_schedule_test_x2 (errbuf OUT VARCHAR2,retcode OUT NUMBER,p_fiscalyear IN NUMBER,p_division IN VARCHAR2 DEFAULT NULL,p_region IN VARCHAR2 DEFAULT NULL,p_salesrep IN NUMBER DEFAULT NULL,p_dealerid IN NUMBER DEFAULT NULL,p_requestid IN NUMBER DEFAULT NULL

)AUTHID CURRENT_USERIS

len NUMBER (10);xmlstr VARCHAR2 (32767);offset NUMBER (10) := 32767;retrieved NUMBER (10) := 0;stmt VARCHAR2 (2000);RESULT CLOB;

v_user_id VARCHAR2 (20);v_error_message VARCHAR2 (240);v_responsibility_name fnd_responsibility_tl.responsibility_name%TYPE;v_application_id fnd_responsibility_tl.application_id%TYPE;v_responsibility_id fnd_responsibility_tl.responsibility_id%TYPE;v_org_id hr_organization_units.organization_id%TYPE;v_dlrid riso_dlr_quota_headers.dealer_id%TYPE;v_executive VARCHAR2 (55);v_title VARCHAR2 (40);v_division VARCHAR2 (40);

Page 6: Generation_XML_PLSQL

Page 6 of 16

v_dlrname ra_addresses.address1%TYPE;v_flexvalueid fnd_flex_values.flex_value_id%TYPE;v_flexvalue fnd_flex_values.flex_value%TYPE;v_terr_line_id riso_dlr_terr_lines_view.terr_line_id%TYPE;v_filename VARCHAR2 (20);v_price_list_id NUMBER (15);v_end VARCHAR2 (15) := 'End of Dealer';v_count_rec NUMBER;e_price_list_id EXCEPTION;e_customername EXCEPTION;e_param_null EXCEPTION;e_two_param EXCEPTION;

CURSOR c_dealersIS

SELECT UPPER (ra.address1) dealer_name,UPPER (rt.segment1) division,rvh.customer_id

FROM ra_addresses ra,riso_dlr_terr_headers_view rvh,ra_site_uses rsu,ra_territories rt,ra_customers rc

WHERE rvh.fiscal_year = p_fiscalyearAND ra.customer_id = rvh.customer_idAND ra.address_id = rsu.address_idAND rc.customer_id = rvh.customer_idAND rsu.site_use_code = 'CONT'AND rc.status = 'A'

AND rsu.status = 'A' AND rsu.territory_id =rt.territory_idAND rvh.customer_id IN (SELECT v_customer_id

FROM riso_schedule_temp_table)ORDER BY dealer_name;

vc_dealers c_dealers%ROWTYPE;

--RISO Printer Duplicator ProductsCURSOR c_products_dupIS

SELECT qplh.description,qplh.attribute6,

Page 7: Generation_XML_PLSQL

Page 7 of 16

TO_NUMBER (qplh.attribute7)FROM qp_list_headers_v qplh, qp_secondary_price_lists_v qpsWHERE qplh.list_header_id = qps.list_header_id

AND qps.parent_price_list_id = TO_CHAR (v_price_list_id)AND qps.description NOT IN ('NON-STOCK PARTS', 'DROPSHIP')AND qps.description NOT LIKE 'LEXMARK%'AND ( qplh.attribute6 IN

('1M', '5S')OR (qplh.attribute6 = '7O'

AND TO_NUMBER (qplh.attribute7) = 150)

)ORDER BY 2, 3;

vc_products_dup c_products_dup%ROWTYPE;

--RISO Printer Duplicator Accessory/Peripheral ProductsCURSOR c_products_accIS

SELECT qplh.description,qplh.attribute6,TO_NUMBER (qplh.attribute7)

FROM qp_list_headers_v qplh, qp_secondary_price_lists_v qpsWHERE qplh.list_header_id = qps.list_header_id

AND qps.parent_price_list_id = TO_CHAR (v_price_list_id)AND qps.description NOT IN ('NON-STOCK PARTS', 'DROPSHIP')AND qps.description NOT LIKE 'LEXMARK%'AND qplh.attribute6 IN ('3A')ORDER BY 2, 3;

vc_products_acc c_products_acc%ROWTYPE;BEGIN

DELETE FROM riso_schedule_temp_table;

EXECUTE IMMEDIATE ('CREATE TABLEUSER_RISO_SCH_TEST2(DEALER_ID VARCHAR2(2000),DEALER_NAMEVARCHAR2(240),FISCAL_YESR VARCHAR2(2000),

PRODUCT_NAME VARCHAR2(2000),PRODUCT_DESCRIPTIONVARCHAR2(2000))'

);COMMIT;

--Ensure at least one of the following parameters is filled in by user.IF p_division IS NULL

Page 8: Generation_XML_PLSQL

Page 8 of 16

AND p_region IS NULLAND p_salesrep IS NULLAND p_dealerid IS NULL

THENRAISE e_param_null;

END IF;

--Ensure ONLY one of the following parameters is filled in by user.IF (p_division IS NOT NULL AND p_region IS NOT NULL)

OR (p_division IS NOT NULL AND p_salesrep IS NOT NULL)OR (p_division IS NOT NULL AND p_dealerid IS NOT NULL)OR (p_region IS NOT NULL AND p_salesrep IS NOT NULL)OR (p_region IS NOT NULL AND p_dealerid IS NOT NULL)OR (p_salesrep IS NOT NULL AND p_dealerid IS NOT NULL)

THENRAISE e_two_param;

END IF;

--Run the riso_dynamicquery_p procedure and pass in whichever parameter--was selected by user, i.e., division, region, salesrep or dealerid.IF (p_division IS NOT NULL)THEN

riso_dynamicquery_p (1, p_fiscalyear, p_division, NULL, NULL, NULL);ELSIF (p_region IS NOT NULL)THEN

riso_dynamicquery_p (2, p_fiscalyear, NULL, p_region, NULL, NULL);ELSIF p_salesrep IS NOT NULLTHEN

riso_dynamicquery_p (3, p_fiscalyear, NULL, NULL, p_salesrep, NULL);ELSIF p_dealerid IS NOT NULLTHEN

riso_dynamicquery_p (4, p_fiscalyear, NULL, NULL, NULL, p_dealerid);END IF;

--Open the dealer cursor and get the name and division of this dealerFOR vc_dealers IN c_dealersLOOP

v_dlrid := vc_dealers.customer_id;

BEGINSELECT UPPER (ra.address1),

UPPER (rt.segment1)

Page 9: Generation_XML_PLSQL

Page 9 of 16

INTO v_dlrname,v_division

FROM ra_addresses ra,riso_dlr_quota_headers_view rqh,ra_site_uses rsu,ra_territories rt

WHERE ra.customer_id = rqh.dealer_idAND rqh.dealer_id = v_dlridAND rqh.fiscal_year = p_fiscalyearAND ra.address_id = rsu.address_idAND rsu.site_use_code = 'CONT'AND rsu.status = 'A'AND rsu.territory_id = rt.territory_id;

EXCEPTIONWHEN NO_DATA_FOUNDTHEN

RAISE e_customername;END;

--Set the executive name and title of person to sign the Schedulev_executive := 'RICHARD M. MYTNIK';v_title := 'VICE PRESIDENT AND GENERAL MANAGER';v_division := 'NORTH AMERICAN DEALER SALES DIVISION';DBMS_OUTPUT.put_line ( 'Dealer: '

|| v_dlrid|| CHR (10)|| v_dlrname|| CHR (10)|| 'Fiscal_Year: '|| p_fiscalyear);

DBMS_OUTPUT.put_line ( 'Executive : '|| v_executive|| CHR (10)|| 'Title: '|| v_title|| CHR (10)|| 'Division: '|| v_division|| ' DIVISION');

Page 10: Generation_XML_PLSQL

Page 10 of 16

BEGINSELECT price_list_id INTO v_price_list_id FROM ar_customers_vWHERE customer_id = v_dlrid;

EXCEPTIONWHEN NO_DATA_FOUNDTHEN

RAISE e_price_list_id;END;

DBMS_OUTPUT.put_line ('PRINTER DUPLICATOR MACHINES,SUPPLIES, PARTS:');

v_count_rec := 0;

--Open the duplicator products cursor to retrieve the products for this dealer's price listFOR vc_products_dup IN c_products_dupLOOP

v_count_rec := v_count_rec + 1;DBMS_OUTPUT.put_line ( 'D Product:'

|| CHR (10)|| UPPER (vc_products_dup.description));

stmt := 'INSERT INTO USER_RISO_SCH_TEST2 VALUES(:1,:2,:3,:4,:5)';

EXECUTE IMMEDIATE stmtUSING TO_CHAR (v_dlrid),

v_dlrname,TO_CHAR (p_fiscalyear),'PRINTER DUPLICATOR MACHINES, SUPPLIES, PARTS',vc_products_dup.description;

END LOOP;IF v_count_rec = 0THEN

NULL;END IF;

DBMS_OUTPUT.put_line('PRINTER DUPLICATOR ACCESSORY/PERIPHERAL

PRODUCTS:');v_count_rec := 0;

--Open the accessories products cursor to retrieve the products for this dealer's price listFOR vc_products_acc IN c_products_acc

Page 11: Generation_XML_PLSQL

Page 11 of 16

LOOPv_count_rec := v_count_rec + 1;DBMS_OUTPUT.put_line ( 'A Product:'

|| CHR (10)|| UPPER (vc_products_acc.description));

stmt := 'INSERT INTO USER_RISO_SCH_TEST2 VALUES(:1,:2,:3,:4,:5)';

EXECUTE IMMEDIATE stmt USINGTO_CHAR (v_dlrid),v_dlrname,TO_CHAR (p_fiscalyear),

‘PRINTER DUPLICATOR ACCESSORY/PERIPHERAL PRODUCTS:A Product',

vc_products_acc.description;END LOOP;IF v_count_rec = 0THENstmt := 'INSERT INTO USER_RISO_SCH_TEST2 VALUES(:1,:2,:3,:4,:5)';

EXECUTE IMMEDIATE stmt USINGTO_CHAR (v_dlrid),v_dlrname,TO_CHAR (p_fiscalyear),'PRINTER DUPLICATOR ACCESSORY/PERIPHERAL PRODUCTS:A

Product','N/A';

END IF;

DBMS_OUTPUT.put_line ('RISO SOLUTIONS PRODUCTS:');v_count_rec := 0;

END LOOP;

SELECT DBMS_XMLGEN.getxml ('SELECT * FROMUSER_RISO_SCH_TEST2')

INTO RESULTFROM DUAL;

len := DBMS_LOB.getlength (RESULT);

LOOP

Page 12: Generation_XML_PLSQL

Page 12 of 16

EXIT WHEN len = retrieved;

IF (len - retrieved) < 32767THEN

SELECT SUBSTR (RESULT, retrieved + 1)INTO xmlstrFROM DUAL;

retrieved := len;fnd_file.put_line (fnd_file.output, xmlstr);

ELSESELECT SUBSTR (RESULT, retrieved + 1, offset)

INTO xmlstrFROM DUAL;

retrieved := retrieved + offset;fnd_file.put_line (fnd_file.output, xmlstr);

END IF;END LOOP;

EXECUTE IMMEDIATE ('drop table USER_RISO_SCH_TEST2');

EXCEPTIONWHEN e_customername THENraise_application_error (-20005, 'No customer found.');WHEN e_price_list_id THENraise_application_error (-20010, 'No Price List ID for this customer.');WHEN e_param_null THENraise_application_error(-20015,'Must enter at least one of: Division, Region, Sales Rep, or Customer.');WHEN e_two_param THENraise_application_error(-20020,'Must enter ONLY one of: Division, Region, Sales Rep, or Customer.');END;

Page 13: Generation_XML_PLSQL

Page 13 of 16

Registering the PL/SQL Package:

Creating Executable

Page 14: Generation_XML_PLSQL

Page 14 of 16

Defining the Program

Assign the Program to corresponding responsibility to run.

Page 15: Generation_XML_PLSQL

Page 15 of 16

Sample Code to get XML which simulates an RDF:

The following code uses a Single select query to retrieve all the data that a Standard InvoiceReport will give out along with the grouping tags. We use the keyword ‘CURSOR’ here to group the data.

CREATE OR REPLACE PROCEDURE xml_cursor_eg (errbuf OUT VARCHAR2,retcode OUT VARCHAR2

)AS

RESULT LONG;BEGIN

SELECT DBMS_XMLGEN.getxml('SELECT rcta.trx_number,

rcta.trx_date,CURSOR (SELECT hl.address1,

hl.address2,hl.postal_code,hl.country

FROM hz_party_sites hps, hz_locations hlWHERE hps.party_site_id = rcta.ship_to_site_use_idAND hps.location_id = hl.location_id

) "SHIP_TO_DETAILS",CURSOR (SELECT hl.address1,

hl.address2,hl.postal_code,hl.country

FROM hz_party_sites hps, hz_locations hlWHERE hps.party_site_id = rcta.bill_to_site_use_idAND hps.location_id = hl.location_id

) "BILL_TO_DETAILS",CURSOR (SELECT hl.address1,

hl.address2,hl.postal_code,hl.country

FROM hz_party_sites hps, hz_locations hlWHERE hps.party_site_id = rcta.remit_to_address_idAND hps.location_id = hl.location_id

) "REMIT_TO_DETAILS",CURSOR (SELECT rctla.customer_trx_line_id,

Page 16: Generation_XML_PLSQL

Page 16 of 16

rctla.line_number,rctla.quantity_ordered,rctla.quantity_invoiced,rctla.description,rctla.unit_selling_price,rctla.uom_code,rctla.quantity_invoiced * rctla.unit_selling_price "LINE_TOTAL"

FROM ra_customer_trx_lines_all rctlaWHERE rcta.customer_trx_id = rctla.customer_trx_id

AND rctla.line_type = ''LINE''ORDER BY rctla.line_number) "LINE_DETAILS",

CURSOR (SELECT SUM (rctla.quantity_invoiced * rctla.unit_selling_price)"INVOIVE_AMT"FROM ra_customer_trx_lines_all rctlaWHERE rcta.customer_trx_id = rctla.customer_trx_idAND rctla.line_type = ''LINE''

) "INVOICE_AMT_TOTAL",CURSOR (SELECT SUM (nvl(rctla.extended_amount,0)) "TAX_AMT"

FROM ra_customer_trx_lines_all rctlaWHERE rcta.customer_trx_id = rctla.customer_trx_idAND rctla.line_type = ''TAX''

) "TAX_AMT_TOTAL",CURSOR (SELECT SUM (DECODE (line_type,''LINE'',

(NVL (rctla.quantity_invoiced, 0)*NVL (rctla.unit_selling_price,0)),0))

+ SUM (DECODE (line_type,''TAX'',NVL (rctla.extended_amount, 0),0)) "TOTAL"

FROM ra_customer_trx_lines_all rctlaWHERE rcta.customer_trx_id = rctla.customer_trx_id

) "TOTAL_AMOUNT"FROM ra_customer_trx_all rctaWHERE rcta.customer_trx_id between 4115 and 4119')

INTO RESULTFROM DUAL;

fnd_file.put_line (fnd_file.output, RESULT);END;

/