Home > Software design >  Oracle XMLTABLE - how to get following result?
Oracle XMLTABLE - how to get following result?

Time:12-09

I need to fetch following result using XMLTABLE function in Oracle 19c database:

HEADER_ATTR2   ITEM_ATTR1   ITEM_ATTR2
attr2          attr11       attr12 
attr2          attr21       attr22 
attr2          attr31       attr32 

from this xml:

<body>
  <header>
    <header_attr1>attr1</header_attr1>
    <header_attr2>attr2</header_attr2>
  </header>
  <item>
    <item_attr1>attr11</item_attr1>
    <item_attr2>attr12</item_attr2>
  </item>
  <item>
    <item_attr1>attr21</item_attr1>
    <item_attr2>attr22</item_attr2>
  </item>
  <item>
    <item_attr1>attr31</item_attr1>
    <item_attr2>attr32</item_attr2>
  </item>
</body>

What is the best way to do that?

CodePudding user response:

You can get your output using:

SELECT *
FROM   XMLTABLE(
         '/body/item'
         PASSING XMLTYPE('<body>
  <header>
    <header_attr1>attr1</header_attr1>
    <header_attr2>attr2</header_attr2>
  </header>
  <item>
    <item_attr1>attr11</item_attr1>
    <item_attr2>attr12</item_attr2>
  </item>
  <item>
    <item_attr1>attr21</item_attr1>
    <item_attr2>attr22</item_attr2>
  </item>
  <item>
    <item_attr1>attr31</item_attr1>
    <item_attr2>attr32</item_attr2>
  </item>
</body>')
         COLUMNS
           header_attr2 VARCHAR2(20) PATH './../header/header_attr2',
           item_attr1 VARCHAR2(20) PATH 'item_attr1',
           item_attr2 VARCHAR2(20) PATH 'item_attr2'
       )
HEADER_ATTR2 ITEM_ATTR1 ITEM_ATTR2
attr2 attr11 attr12
attr2 attr21 attr22
attr2 attr31 attr32

db<>fiddle here

CodePudding user response:

The standard way to extract data from multi-level XML (data nested at different levels) is to cascade the calls to xmltable. Something like this; notice how the nested "document" <item> is extracted as xmltype in the first pass, and then passed on as the basis for the second call to xmltable.

select t.id, x1.header_attr1, x1.header_attr2, x2.item_attr1, x2.item_attr2
from   t
       cross apply
       xmltable('/body' passing xmltype(xmlstr)
           columns header_attr1 varchar2(20) path 'header/header_attr1',
                   header_attr2 varchar2(20) path 'header/header_attr2',
                   item         xmltype      path 'item'
       ) x1
       cross apply
       xmltable('/item' passing item
           columns item_attr1 varchar2(20) path 'item_attr1',
                   item_attr2 varchar2(20) path 'item_attr2'
       ) x2
;

This will produce the following output:

    ID HEADER_ATTR1     HEADER_ATTR2     ITEM_ATTR1       ITEM_ATTR2      
------ ---------------- ---------------- ---------------- --------------
  3001 attr1            attr2            attr11           attr12          
  3001 attr1            attr2            attr21           attr22          
  3001 attr1            attr2            attr31           attr32          
  2048 attr201          attr202          attr--11         attr--12        
  2048 attr201          attr202          attr--21         attr--22        
  2048 attr201          attr202          attr--31         attr--32    

from the following sample data:

create table t (id, xmlstr) as
select 3001,
'<body>
  <header>
    <header_attr1>attr1</header_attr1>
    <header_attr2>attr2</header_attr2>
  </header>
  <item>
    <item_attr1>attr11</item_attr1>
    <item_attr2>attr12</item_attr2>
  </item>
  <item>
    <item_attr1>attr21</item_attr1>
    <item_attr2>attr22</item_attr2>
  </item>
  <item>
    <item_attr1>attr31</item_attr1>
    <item_attr2>attr32</item_attr2>
  </item>
</body>'
from dual union all
select 2048,
'<body>
  <header>
    <header_attr1>attr201</header_attr1>
    <header_attr2>attr202</header_attr2>
  </header>
  <item>
    <item_attr1>attr--11</item_attr1>
    <item_attr2>attr--12</item_attr2>
  </item>
  <item>
    <item_attr1>attr--21</item_attr1>
    <item_attr2>attr--22</item_attr2>
  </item>
  <item>
    <item_attr1>attr--31</item_attr1>
    <item_attr2>attr--32</item_attr2>
  </item>
</body>'
from dual;
  • Related