Oracle解析含多子节点XML遇ORA-19279错误,求解决方案
问题描述
解析包含多个<quickFilterValues>子元素的XML时,持续触发ORA-19279: XPTY0004 - XQuery动态类型不匹配:期望单例序列,却得到多项目序列错误,需要提取所有<quickFilterValues>节点的去重值。
待解析XML
<dataView> <categoryId>22</categoryId> <tableReferenceId>2533050</tableReferenceId> <noOfColumnsToFixHorizontally>0</noOfColumnsToFixHorizontally> <fieldOptions> <id>2533805</id> <fieldId>2446226</fieldId> <entityId>2446223</entityId> <fieldHeaderLabel>Product ID</fieldHeaderLabel> <displayedByDefault>true</displayedByDefault> <filterableAndSortable>true</filterableAndSortable> <quickFilterValues>Laptops</quickFilterValues> <quickFilterValues>Monitors</quickFilterValues> <quickFilterValues>PCs</quickFilterValues> <columnWidth>MEDIUM_SMALL</columnWidth> <fieldType>DVFO_DATA</fieldType> </fieldOptions> <fieldOptions> <id>2533806</id> <fieldId>563</fieldId> <fieldHeaderLabel>Quarter</fieldHeaderLabel> <displayedByDefault>true</displayedByDefault> <filterableAndSortable>true</filterableAndSortable> <quickFilterValues>Quarter 3 2016</quickFilterValues> <quickFilterValues>Quarter 4 2016</quickFilterValues> <quickFilterValues>Quarter 1 2017</quickFilterValues> <quickFilterValues>Quarter 2 2017</quickFilterValues> <columnWidth>MEDIUM_SMALL</columnWidth> <fieldType>DVFO_DATA</fieldType> </fieldOptions> </dataView>
期望输出
| quick_filter_value |
|---|
| Laptops |
| Monitors |
| PCs |
| Quarter 3 2016 |
| Quarter 4 2016 |
| Quarter 1 2017 |
| Quarter 2 2017 |
错误的尝试语句
with plm as (select '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dataView><categoryId>22</categoryId><tableReferenceId>2533050</tableReferenceId><noOfColumnsToFixHorizontally>0</noOfColumnsToFixHorizontally><fieldOptions><id>2533805</id><fieldId>2446226</fieldId><entityId>2446223</entityId><fieldHeaderLabel>Product ID</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Laptops</quickFilterValues><quickFilterValues>Monitors</quickFilterValues><quickFilterValues>PCs</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions><fieldOptions><id>2533806</id><fieldId>563</fieldId><fieldHeaderLabel>Quarter</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Quarter 3 2016</quickFilterValues><quickFilterValues>Quarter 4 2016</quickFilterValues><quickFilterValues>Quarter 1 2017</quickFilterValues><quickFilterValues>Quarter 2 2017</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions></dataView> ' x from dual) SELECT * FROM plm, XMLTable('/dataView/fieldOptions' PASSING xmltype(x) COLUMNS fo VARCHAR2(250) PATH 'quickFilterValues' )
触发的错误信息
ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence
19279. 00000 - "XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence"
*Cause: The XQuery sequence passed in had more than one item.
*Action: Correct the XQuery expression to return a single item sequence.
解决方案
错误原因
原查询中,每个<fieldOptions>节点下包含多个<quickFilterValues>子节点,当直接将quickFilterValues路径映射到单个VARCHAR2列时,Oracle期望获取单个值,但实际得到多个值的序列,因此触发类型不匹配错误。
方法1:直接定位目标节点
直接用XMLTable遍历所有<quickFilterValues>节点,每个节点返回一行,再通过DISTINCT去重:
with plm as (select '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dataView><categoryId>22</categoryId><tableReferenceId>2533050</tableReferenceId><noOfColumnsToFixHorizontally>0</noOfColumnsToFixHorizontally><fieldOptions><id>2533805</id><fieldId>2446226</fieldId><entityId>2446223</entityId><fieldHeaderLabel>Product ID</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Laptops</quickFilterValues><quickFilterValues>Monitors</quickFilterValues><quickFilterValues>PCs</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions><fieldOptions><id>2533806</id><fieldId>563</fieldId><fieldHeaderLabel>Quarter</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Quarter 3 2016</quickFilterValues><quickFilterValues>Quarter 4 2016</quickFilterValues><quickFilterValues>Quarter 1 2017</quickFilterValues><quickFilterValues>Quarter 2 2017</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions></dataView>' x from dual) SELECT DISTINCT qfv.value AS quick_filter_value FROM plm, XMLTable('/dataView/fieldOptions/quickFilterValues' PASSING xmltype(x) COLUMNS value VARCHAR2(250) PATH '.' ) qfv;
方法2:嵌套XMLTable遍历层级
先遍历所有<fieldOptions>节点,再嵌套遍历每个节点下的<quickFilterValues>,最后去重:
with plm as (select '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><dataView><categoryId>22</categoryId><tableReferenceId>2533050</tableReferenceId><noOfColumnsToFixHorizontally>0</noOfColumnsToFixHorizontally><fieldOptions><id>2533805</id><fieldId>2446226</fieldId><entityId>2446223</entityId><fieldHeaderLabel>Product ID</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Laptops</quickFilterValues><quickFilterValues>Monitors</quickFilterValues><quickFilterValues>PCs</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions><fieldOptions><id>2533806</id><fieldId>563</fieldId><fieldHeaderLabel>Quarter</fieldHeaderLabel><displayedByDefault>true</displayedByDefault><filterableAndSortable>true</filterableAndSortable><quickFilterValues>Quarter 3 2016</quickFilterValues><quickFilterValues>Quarter 4 2016</quickFilterValues><quickFilterValues>Quarter 1 2017</quickFilterValues><quickFilterValues>Quarter 2 2017</quickFilterValues><columnWidth>MEDIUM_SMALL</columnWidth><fieldType>DVFO_DATA</fieldType></fieldOptions></dataView>' x from dual) SELECT DISTINCT qfv.value AS quick_filter_value FROM plm, XMLTable('/dataView/fieldOptions' PASSING xmltype(x) COLUMNS qfvs XMLTYPE PATH 'quickFilterValues' ) fo, XMLTable('/quickFilterValues' PASSING fo.qfvs COLUMNS value VARCHAR2(250) PATH '.' ) qfv;
内容的提问来源于stack exchange,提问作者Lucian Lazar

