Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PL/SQL error on saving of Nested XML in table

I am trying to save XML in a table. The XML has a format like the following:

<employees>
  <employees_id> 1</employees_id>
  <employees_name>Teradata</employees_name>
     <department_id>100</department_id>
     <department_name>Techinical</department_name>
     <department_id>200</department_id>
     <department_name>Management</department_name>
     <department_id>300</department_id>
     <department_name>Telecom</department_name>
  </employees>
  <employees>
  <employees_id> 2</employees_id>
  <employees_name>AT&T</employees_name>
     <department_id>400</department_id>
     <department_name>Techinical</department_name>
     <department_id>500</department_id>
     <department_name>Management</department_name>
     <department_id>600</department_id>
     <department_name>Telecom</department_name>
  </employees>

My table has only an id column and xmltype column.

The procedure which I am using is as follows:

   DECLARE
   CTX         DBMS_XMLGEN.CTXHANDLE;
   LCLOB$XML_AS_CLOB  CLOB;
   LREC$EMPLOYEES_EMPNO NUMBER;
 BEGIN
  FOR LREC$EMPLOYEES_EMPNO IN (198, 197, 180)
   LOOP
    --Create context for XML
    CTX :=
      DBMS_XMLGEN.NEWCONTEXT (
       'SELECT employees.EMPLOYEE_ID, employees.FIRST_NAME, 
        departments.DEPARTMENT_ID, departments.DEPARTMENT_NAME
        FROM EMPLOYEES, departments
        WHERE employees.department_id = departments.department_id and 
        employees.employees_id =' || LREC$EMPLOYEES_EMPNO);
    --Get XML file of Context
     -- Set the row header to be EMPLOYEE
    DBMS_XMLGEN.setRowTag(CTX, 'EMPLOYEE');
    LCLOB$XML_AS_CLOB := DBMS_XMLGEN.GETXML (CTX);
    DBMS_XMLGEN.CLOSECONTEXT (CTX); 
    INSERT INTO HR.OFFLINE_XML (id, XML_FILE)
       VALUES ( LREC$EMPLOYEES_EMPNO, XMLTYPE (LCLOB$XML_AS_CLOB));
    END LOOP;
   COMMIT;
 END;

Error report:

 ORA-06550: line 7, column 4:
PLS-00103: Encountered the symbol "LOOP" when expecting one of the following:

   * & - + / at mod remainder rem .. <an exponent (**)> ||
   multiset year day
ORA-06550: line 18, column 16:
PLS-00103: Encountered the symbol "." when expecting one of the following:

   constant exception <an identifier>
   <a double-quoted delimited-identifier> table long double ref
   char time timestamp interval date binary national charac
ORA-06550: line 19, column 23:
PLS-00103: Encountered the symbol "=" when expecting one of the following:

   constant exception <an identifier>
   <a double-quoted delimited-identifier> table long double ref
   char time timestamp interval date binary national charac
ORA-06550: line 20, column 16:
PLS-00103: Encountered the symbol "." when expecting one of the following:

   constant exception <an identifier>
   <a double-quoted delimited-identifier> table long double ref
   char time timestamp interval date binary national charac
ORA-06550: line 21, column 5:
PLS-00103: Encountered the symbol "INSERT" when expecting one of the following:

   begin function pragma procedure subtype type <an identifier>
   <a double-quoted delimited-identifier> current cursor delete
   exists prior
The symbol "b
ORA-06550: line 24, column 4:
PLS-00103: Encountered the symbol "COMMIT" when expecting one of the following:

   end not pragma final instantiable order overriding static
   member constructor map
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:
like image 379
Femme Fatale Avatar asked Apr 13 '26 22:04

Femme Fatale


1 Answers

As Noel said, you can't supply fixed values to a for loop like that. (All the other errors in your report are knock-ons from that, though there are other problems). You can supply a range, as for i in 1..10 loop, but that doesn't help you here, even for your sample data. As it's just for testing you can use a dummy cursor for now:

    FOR LREC$EMPLOYEES_EMPNO IN (
        SELECT 198 AS employee_id FROM dual
        UNION ALL SELECT 197 FROM dual 
        UNION ALL SELECT 180 FROM dual
    ) LOOP

(Although I actually prefer DazzaL's array, but I'll stick with this for now). You don't have to declare the cursor, and the number variable you declared with that name will be superseded by this version. And when you refer to one of the values it returns it has to be by name, so in this case LREC$EMPLOYEES_EMPNO.employee_id. Persoanlly I'd go for a shorter name *8-)

As DazzaL also mentioned you don't need the intermediate CLOB either. It also seems unnecessary to create and close the context each time around the loop, when you can use a bind variable instead.

This works and gets the same result as your version (suitable amended), but not the output you suggested you wanted in the question:

DECLARE
    ctx DBMS_XMLGEN.CTXHANDLE;
BEGIN
    ctx := DBMS_XMLGEN.NEWCONTEXT(
       'SELECT employees.EMPLOYEE_ID, employees.FIRST_NAME, 
        departments.DEPARTMENT_ID, departments.DEPARTMENT_NAME
        FROM EMPLOYEES, departments
        WHERE employees.department_id = departments.department_id and      
        employees.employee_id = :id');
    DBMS_XMLGEN.setRowTag(ctx, 'EMPLOYEE');
    FOR r IN (
        SELECT 198 AS employee_id FROM dual
        UNION ALL SELECT 197 FROM dual 
        UNION ALL SELECT 180 FROM dual
    ) LOOP
        DBMS_XMLGEN.SETBINDVALUE(ctx, 'ID', r.employee_id);
        INSERT INTO OFFLINE_XML (id, xml_file)
        VALUES (r.employee_id, DBMS_XMLGEN.GETXMLTYPE(ctx));
    END LOOP;
    DBMS_XMLGEN.CLOSECONTEXT(ctx); 
END;
/

Which populates the table with:

        ID XML_FILE
---------- --------------------------------------------------
       198 <ROWSET>
             <EMPLOYEE>
               <EMPLOYEE_ID>198</EMPLOYEE_ID>
               <FIRST_NAME>Bob</FIRST_NAME>
               <DEPARTMENT_ID>1</DEPARTMENT_ID>
               <DEPARTMENT_NAME>First</DEPARTMENT_NAME>
             </EMPLOYEE>
           </ROWSET>

       197 <ROWSET>
             <EMPLOYEE>
               <EMPLOYEE_ID>197</EMPLOYEE_ID>
               <FIRST_NAME>Adam</FIRST_NAME>
               <DEPARTMENT_ID>1</DEPARTMENT_ID>
               <DEPARTMENT_NAME>First</DEPARTMENT_NAME>
             </EMPLOYEE>
           </ROWSET>

       180 <ROWSET>
             <EMPLOYEE>
               <EMPLOYEE_ID>180</EMPLOYEE_ID>
               <FIRST_NAME>Charlie</FIRST_NAME>
               <DEPARTMENT_ID>2</DEPARTMENT_ID>
               <DEPARTMENT_NAME>Second</DEPARTMENT_NAME>
             </EMPLOYEE>
           </ROWSET>
like image 92
Alex Poole Avatar answered Apr 16 '26 11:04

Alex Poole



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!