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
答案 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。)