您可以使用 XMLTable 提取多个值,包括父元素值,例如:
select printerId, printerDate, countryCd
from xmltable(
'/printer/printer-header/elem[@name="printerLocations"]'
passing xmltype('<?xml version="1.0" encoding="UTF16" standalone="no" ?>
<printer>
<printer-header>
<elem name="printerId">XROX101-19341</elem>
<elem name="printerDate">05/11/19 12:27:48</elem>
<elem name="printerLocations">
<elem name="countryCd">USA</elem>
</elem>
<elem name="printerLocations">
<elem name="countryCd">UK</elem>
</elem>
<elem name="printerLocations">
<elem name="countryCd"/>
</elem>
</printer-header>
</printer>')
columns
printerId varchar2(30) path './../elem[@name="printerId"]',
printerDate varchar2(17) path './../elem[@name="printerDate"]',
countryCd varchar2(3) path 'elem[@name="countryCd"]'
)
| PRINTERID |
PRINTERDATE |
COUNTRYCD |
| XROX101-19341 |
05/11/19 12:27:48 |
USA |
| XROX101-19341 |
05/11/19 12:27:48 |
UK |
| XROX101-19341 |
05/11/19 12:27:48 |
null |
假设它是固定格式,您可以将“printDate”值转换为实际日期。
无论哪种方式,您都可以将其用作内联视图或 CTE。
db<>fiddle
我尝试了什么:
从打印机中选择 XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"]/elem[@name="countryCd"]/text()').getStringVal()
这会将所有国家/地区值作为单个字符串获取;使用 XMLTable 代替分别获取每个值,并允许您轻松获取其他数据,以及一次获取多个 XML 文档的数据。
由于您的字符串来自表格,因此变为:
select x.printerId, x.printerDate, x.countryCd
from printers p
cross apply xmltable(
'/printer/printer-header/elem[@name="printerLocations"]'
passing xmltype(p.xml_string)
columns
printerId varchar2(30) path './../elem[@name="printerId"]',
printerDate varchar2(17) path './../elem[@name="printerDate"]',
countryCd varchar2(3) path 'elem[@name="countryCd"]'
) x
| PRINTERID |
PRINTERDATE |
COUNTRYCD |
| XROX101-19341 |
05/11/19 12:27:48 |
USA |
| XROX101-19341 |
05/11/19 12:27:48 |
UK |
| XROX101-19341 |
05/11/19 12:27:48 |
null |
它包含在外部查询中,转换后的日期为:
select * from (
select
printerId,
to_date(printerDate, 'DD/MM/RR HH24:MI:SS') as printerDate,
countryCd
from printers p
cross apply xmltable(
'/printer/printer-header/elem[@name="printerLocations"]'
passing xmltype(p.xml_string)
columns
printerId varchar2(30) path './../elem[@name="printerId"]',
printerDate varchar2(17) path './../elem[@name="printerDate"]',
countryCd varchar2(3) path 'elem[@name="countryCd"]'
)
) x
where x.countryCd = 'USA'
| PRINTERID |
PRINTERDATE |
COUNTRYCD |
| XROX101-19341 |
2019-11-05 12:27:48 |
USA |
db<>fiddle
我只需要一张三列表格
您可以调整该结果;但更简单地说,您可以使用类似的方法,按索引定位每个打印机位置:
select x.countryCd1, x.countryCd2, x.countryCd3
from printers p
cross apply xmltable(
'/printer/printer-header'
passing xmltype(p.xml_string)
columns
countryCd1 varchar2(3) path 'elem[@name="printerLocations"][1]/elem[@name="countryCd"]',
countryCd2 varchar2(3) path 'elem[@name="printerLocations"][2]/elem[@name="countryCd"]',
countryCd3 varchar2(3) path 'elem[@name="printerLocations"][3]/elem[@name="countryCd"]'
) x
| COUNTRYCD1 |
COUNTRYCD2 |
COUNTRYCD3 |
| USA |
UK |
null |
db<>fiddle
您可以改为使用三个 XMLQuery 调用,但这会涉及更多重复。
或者,如果您真的愿意,您仍然可以使用您的原始摘录 3 次,并添加一个索引:
select
XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][1]/elem[@name="countryCd"]/text()').getStringVal() as countryCd1,
XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][2]/elem[@name="countryCd"]/text()').getStringVal() as countryCd2,
XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][3]/elem[@name="countryCd"]/text()').getStringVal() as countryCd3
from printers
...gets the same result.
无论哪种方式,您都必须提前知道最终结果中有多少值(列)。 (否则你必须使用动态SQL...)