XML Oracle : Multiple Child Node extract

29,336

You can achieve desired result by using XMLTable() function:

select q.Lastname
     , q.Numberid
     , s.codeid
     , w.LoginId
     , q.address
  from t1 t
  left join xmltable('/begin/entry'
                      passing t.xml_col 
                      columns LastName   varchar2(21)  path 'lastname',
                              NumberId   number        path 'NumberList/number',
                              Address    varchar2(201) path 'address/addresslist',
                              CodeList   XmlType       Path 'NumberList/codelist/code',
                              Logins     XmlType       Path 'NumberList/login/user'
                      ) q
    on (1=1) 
  left join xmltable('/code'
                      passing q.CodeList
                      columns CodeId number path '.') s
    on (1=1)
  left join   xmltable('/user'
                        passing q.Logins
                        columns LoginId varchar2(11) path '.') w
    on (1=1)

Result: SQLFiddle Demo

Lastname Numberid Codeid Loginid Address 
---------------------------------------------------------------------------
gordon   100      213    user1   Jl. jalan pelan-pelan ke Bekasi, Indonesia 
gordon   100      213    user2   Jl. jalan pelan-pelan ke Bekasi, Indonesia 
gordon   100      214    user1   Jl. jalan pelan-pelan ke Bekasi, Indonesia 
gordon   100      214    user2   Jl. jalan pelan-pelan ke Bekasi, Indonesia 
mark     null     null   null    Jl. jalan cepet-cepet ke Jakarta, Indonesia 

Find out more about XMLTable() function.

Note: Working with Oracle releases prior to 11.2.0.2, you can encounter ORA-1780 error(bug 8545377) on certain types of XML queries when cursor_sharing parameter is set to FORCE or SIMILAR(deprecated starting from 11.2). Setting cursor_sharing parameter to EXACT(default value), will solve the problem.

Share:
29,336
zrosystem
Author by

zrosystem

404 not found

Updated on July 12, 2022

Comments

  • zrosystem
    zrosystem almost 2 years

    I have an xml code :

    <begin>
        <entry>
            <lastname>gordon</lastname>
            <NumberList>
                <number>100</number>
                <codelist>
                     <code>213</code>
                     <code>214</code>
                <codelist>
                <login>
                     <user>user1</user>
                     <user>user2</user>
                </login>
            <NumberList>
            <address>
                <addresslist>Jl. jalan pelan-pelan ke Bekasi, Indonesia</addresslist>
            </address>
        </entry>
        <entry>
            <lastname>mark</lastname>
            <address>
                <addresslist>Jl. jalan cepet-cepet ke Jakarta, Indonesia</addresslist>
            </address>
        </entry>
    </begin>
    

    my code:

    FOR r IN (SELECT VALUE(p) col_val,
                     EXTRACT(VALUE(P), '/entry/codelist') AS code,
                     EXTRACT(VALUE(P), '/entry/login') AS login
               FROM TABLE(XMLSequence(Extract(x,'/begin/entry'))) p)
    LOOP
       IF r.col_val.existsnode('/entry/lastname/text()') > 0 
       THEN
          vc_lastname := r.col_val.extract('/sdnEntry/lastname/text()').getstringval();
       END IF;
    
       IF r.col_val.existsnode('/entry/address/addresslist/text()') > 0 
       THEN
        vc_address := r.col_val.extract('/sdnEntry/address/addresslist/text()').getstringval();
       END IF;
    
       IF r.col_val.existsnode('/entry/codelist/id/code/text()') > 0 AND r.col_val.existsnode('/entry/login/user/text()') > 0 
       THEN
          FOR R1 IN (SELECT EXTRACTVALUE(VALUE(T1), '/codelist/code/text()') AS code
                       FROM TABLE(XMLSEQUENCE(EXTRACT(R.code, '/codelist'))) T1)
          LOOP
             DBMS_OUTPUT.PUT_LINE(vc_uid||' - '||vc_firstName||' - '||R1.code||' - '||R2.address);
          END LOOP;
    
          FOR R2 IN (SELECT
                            EXTRACTVALUE(VALUE(T1), '/login/user/text()') AS user
                       FROM TABLE(XMLSEQUENCE(EXTRACT(R.address, 'login/'))) T1)
          LOOP
             DBMS_OUTPUT.PUT_LINE(vc_uid||' - '||vc_firstName||' - '||R2.user||' - '||R2.address);
          END LOOP;
      ELSE
            DBMS_OUTPUT.PUT_LINE(vc_uid||' - '||vc_firstName);
      END IF;
    

    My problem : How to loop child nodes so the data will become like this :

    LastName | Number | code    | user  |   address
    gordon   | 100    | 213     | user1 |Jl. jalan pelan-pelan ke Bekasi, Indonesia
    gordon   | 100    | 213     | user2 |Jl. jalan pelan-pelan ke Bekasi, Indonesia
    gordon   | 100    | 214     | user1 |Jl. jalan pelan-pelan ke Bekasi, Indonesia
    gordon   | 100    | 214     | user2 |Jl. jalan pelan-pelan ke Bekasi, Indonesia
    mark     | Null   | null    | null  |Jl. jalan cepet-cepet ke Jakarta, Indonesia
    

    Any help would be appreciate.

  • ajmalmhd04
    ajmalmhd04 over 10 years
    great!!.. helpful for me.
  • ajmalmhd04
    ajmalmhd04 over 10 years
    why is it raising ORA-01780: string literal required error if I did not set `alter session set cursor_sharing = exact;' ?? Im using 11g
  • ajmalmhd04
    ajmalmhd04 over 10 years
    ok thanks for the info !! hope you meant sharing instead of shearing
  • zrosystem
    zrosystem over 10 years
    wow its working!! thx very much !! i'm using 10g anyway no prob with codes above
  • dokgu
    dokgu over 7 years
    I apologize for injecting my question here but I'm trying to use your solution to my problem and it's giving me blank results. In my case, t1.xml_col is of type NCLOB if that helps.