XMLTABLE,XQUERY-预期的单例序列

时间:2019-04-17 08:32:55

标签: sql xml oracle xmltable

XML:

<import>
    <persons>
        <person>
            <pm>57924160</pm>
            <date_from>2018-05-01</date_from>
            <info>
                <set>
                    <indflag>0</indflag>
                </set>
                <items>
                    <item>
                        <symbol>a</symbol>
                        <date>2018-05-02</date>
                        <cost>190</cost>
                    </item>
                    <item>
                        <symbol>b</symbol>
                        <date>2018-05-02</date>
                        <cost>130</cost>
                    </item>
                </items>
            </info>
        </person>
    </persons>
    <persons>
        <person>
            <pm>57924160</pm>
            <date_from>2018-05-01</date_from>
            <info>
                <set>
                    <indflag>0</indflag>
                </set>
                <items>
                    <item>
                        <symbol>a</symbol>
                        <date>2018-05-02</date>
                        <cost>190</cost>
                    </item>
                    <item>
                        <symbol>b</symbol>
                        <date>2018-05-02</date>
                        <cost>130</cost>
                    </item>
                </items>
            </info>
        </person>
    </persons>
</import>

然后我通过以下方式循环读取此xml:

 SELECT xt.*
   FROM  XMLTABLE(
         '//import/persons/person'
         PASSING xmltype('above_xml')
         COLUMNS 
           pm        VARCHAR2(4)  PATH 'pm',
           indflag   VARCHAR2(10) PATH 'info/set/indflag'
         ) xt;

但是如果我添加另一列

item      varchar2(10) PATH 'info/items/item/symbol'

它给了我ORA,因为xmltable期望每人1个值,并且人身上有两个项目。

我当然可以在pl / sql中处理它,例如获得全人节点,选择所有项目等,但是我想知道是否可以在单个查询中完成以获取输出,如:

PM    INDFLAG  item
5792    0        a
5792    0        b

1 个答案:

答案 0 :(得分:1)

您可以使用两个级别的XMLTable:

select x1.pm, x1.indflag, x2.item
  from  xmltable(
         '//import/persons/person'
         passing xmltype('above_xml')
         columns 
           pm        varchar2(4)  path 'pm',
           indflag   varchar2(10) path 'info/set/indflag',
           items     xmltype      path 'info/items'
         ) x1
  cross join  xmltable(
         '/items/item'
         passing x1.items
         columns 
           item      varchar2(10) PATH 'symbol'
         ) x2;

PM   INDFLAG    ITEM      
---- ---------- ----------
5792 0          a         
5792 0          b         
5792 0          a         
5792 0          b         

或不太灵活,但是这里只有一个子集合,可以,从项目级别开始,然后备份更高级别的节点数据:

select xt.pm, xt.indflag, xt.item
  from  xmltable(
         '//import/persons/person/info/items/item'
         passing xmltype('above_xml')
         columns 
           pm        varchar2(4)  path './../../../pm',
           indflag   varchar2(10) path './../../set/indflag',
           item      varchar2(10) PATH 'symbol'
         ) xt;

PM   INDFLAG    ITEM      
---- ---------- ----------
5792 0          a         
5792 0          b         
5792 0          a         
5792 0          b         

(第二种方法似乎不能在11.2.0.2中起作用,这肯定是一个错误;它确实可以在11.2.0.4和更高版本中使用,包括18c。)