如何将分层数据作为XML进行查询

时间:2015-10-27 08:32:10

标签: sql oracle

我有一张这样的表:

      COL1 COL2             COL3
---------- ---------- ----------
         T1 Direct              M1
         T1 Direct              M2
         T1 List                M3
         M3 Direct              M4
         M3 Direct              M5
         M3 List                M6
         M6 Direct              M7
         M6 Direct              M8
         T2 Direct              M9

Col2 - '直接'说Col3是Col1的直接孩子。

Col2 - '列表'说Col3是Col1的子列表。

因此,对于上述示例,T1具有M1,M2作为直接子项,M3是子子项。再次,M3有M4,M5直接孩子和M6作为子孩子。它继续。

我需要在上面使用Oracle查询转换为XML,如下所示。

 <ROOT>
 <T1>
    <M1/>
    <M2/>
    <M3>
       <M4/>
       <M5/>
       <M6>
         <M7/>
         <M8/>
       <M6/>
    <M3/>
 <T1/>
 <T2>
   <M9 />
 <T2>
 </ROOT>

如何获得上述XML结果?我允许在表格中添加其他条目,以便将整个xml保留在<ROOT>代码中。

1 个答案:

答案 0 :(得分:2)

XML节点名称不能以数字开头,因此您显示的输出无效。您可以使用不同的名称获取结构,或使用这些值来获取属性。

从获取层次结构的查询开始(col2似乎与此无关,它只是描述仅存在于col1col3的层次结构:

select lpad(' ', level) || col3
from t42
connect by col1 = prior col3 and col1 != col3
start with col1 = col3;

LPAD('',LEVEL)||COL3                                                           
--------------------------------------------------------------------------------
 1                                                                              
  2                                                                             
  3                                                                             
   4                                                                            
   5                                                                            
   6                                                                            
    7                                                                           
    8                                                                           

然后,您可以将它们转换为XML元素,在这种情况下使用固定字符,以使它们成为有效名称:

select level, xmlelement(evalname 'x' || col3)
from t42
connect by col1 = prior col3 and col1 != col3
start with col1 = col3;

     LEVEL XMLELEMENT(EVALNAME'X'||COL3)                                             
---------- --------------------------------------------------------------------------------
         1 <x1></x1>
         2 <x2></x2>
         2 <x3></x3>
         3 <x4></x4>
         3 <x5></x5>
         3 <x6></x6>
         4 <x7></x7>
         4 <x8></x8>

然后,您可以在dbms_xmlgen.newContextFromHierarchy call中使用该查询:

select dbms_xmlgen.getxmltype(
  dbms_xmlgen.newcontextfromhierarchy(
    q'[select level, xmlelement(evalname 'x' || col3)
      from t42
      connect by col1 = prior col3 and col1 != col3
      start with col1 = col3]')) as result
from dual;

RESULT                                                                         
--------------------------------------------------------------------------------
<?xml version="1.0"?>
<x1>
  <x2/>
  <x3>
    <x4/>
    <x5/>
    <x6>
      <x7/>
      <x8/>
    </x6>
  </x3>
</x1>

或作为属性:

select dbms_xmlgen.getxmltype(
  dbms_xmlgen.newcontextfromhierarchy(
    q'[select level,
        xmlelement("x", xmlattributes(level as "level", col3 as "col3"))
      from t42
      connect by col1 = prior col3 and col1 != col3
      start with col1 = col3]')) as result
from dual;

RESULT                                                                         
--------------------------------------------------------------------------------
<?xml version="1.0"?>
<x level="1" col3="1">
  <x level="2" col3="2"/>
  <x level="2" col3="3">
    <x level="3" col3="4"/>
    <x level="3" col3="5"/>
    <x level="3" col3="6">
      <x level="4" col3="7"/>
      <x level="4" col3="8"/>
    </x>
  </x>
</x>

如果您真的想要,可以将第一个版本转换为字符串并删除虚拟字符:

select replace(
  dbms_xmlgen.getxmltype(
    dbms_xmlgen.newcontextfromhierarchy(
      q'[select level, xmlelement(evalname 'x' || col3)
        from t42
        connect by col1 = prior col3 and col1 != col3
        start with col1 = col3]')).getstringval(),
  'x', null) as result
from dual;

RESULT                                                                         
--------------------------------------------------------------------------------
<?ml version="1.0"?>                                                            
<1>                                                                             
  <2/>                                                                          
  <3>                                                                           
    <4/>                                                                        
    <5/>                                                                        
    <6>                                                                         
      <7/>                                                                      
      <8/>                                                                      
    </6>                                                                        
  </3>                                                                          
</1>

或大型文档的等效getclobval()。但现在这是一个字符串,而不是真正的XML;如果您尝试将其转换回XMLType,则会收到类似“LPX-00231:在名称或Nmtoken中找到的无效字符49('1')”的错误。无论如何,你可能会接受一些东西。