如何从xmltable中的不同级别获取数据?

how to get data from different levels in a xmltable?

我正在尝试从 VENDOR_XML 列的 table MVR_DTL 中获取两个属性的值。 VENDOR_XML 是 clob 数据类型,包含一个 xml 看起来像这样

<MVRCHPINFF_1.0>
   <Routing ReplyToQMgr="PQ21" ReplyToQ="A4218QA.BIZTALK.REPLY.REPORT.PROD" CorelId="712393102361590" MsgType="8" Expiry="-1" MsgID="201904051632015"></Routing>
   <MVRRecLoop>
      <CLoop>
         <CRec>
            <C_MVRNumberAddr>ROMAN GENERAL</C_MVRNumberAddr>
         </CRec>
         <CRec>
            <C_MVRNumberAddr>ROMAN ST</C_MVRNumberAddr>
         </CRec>
         <CRec>
            <C_MVRNumberAddr>ROMAN CITY, ROME 111111</C_MVRNumberAddr>
         </CRec>
      </CLoop>
      <HIJLoop>
         <JRec>
            <J_SVCDesc>MVR RECORD CLEAR</J_SVCDesc>
         </JRec>
      </HIJLoop>
      </MVRRecLoop>
</MVRCHPINFF_1.0>

我试过了运行

SELECT c.J_SVCDesc, c.XMLDetails from MVR_DTL M,
    XMLTABLE(
        'string-join(/MVRCHPINFF_1.0/MVRRecLoop/CLoop/CRec/C_MVRNumberAddr, "|")'
    passing XMLTYPE(M.VENDOR_XML)
    columns XMLDetails varchar2(200) PATH '.',
            J_SVCDesc varchar2(50) PATH './../../../HIJLoop/JRec/J_SVCDesc') c;

我收到这个错误

Error during Execute
 S1000(19112)[Oracle][ODBC][Ora]ORA-19112: error raised during evaluation: 
XVM-01020: [XPTY0020] The path step context item is not a node

我也试过了

SELECT x1.J_SVCDesc, x2.XMLDetails from MVR_DTL M,  
XMLTABLE('/MVRCHPINFF_1.0/MVRRecLoop'
passing XMLTYPE(M.VENDOR_XML)
columns 
Address XMLTYPE path './CLoop/CRec/C_MVRNumberAddr',
J_SVCDesc varchar(50) PATH './HIJLoop/JRec/J_SVCDesc') x1
CROSS JOIN XMLTable(
  'string-join(., "|")'
  PASSING x1.Address
  COLUMNS XMLDetails varchar2(200) PATH '.') x2;

但出错了

Error during Execute
 S1000(19279)[Oracle][ODBC][Ora]ORA-19279: XPTY0004 - XQuery dynamic type mismatch: 
expected singleton sequence - got multi-item sequence

我正在尝试获取

J_SVCDESC           XMLDETAILS
MVR RECORD CLEAR    ROMAN GENERAL|ROMAN ST|ROMAN CITY, ROME 111111

谁能帮我弄清楚我错过了什么。

您可以将字符串连接向下移动到列子句:

select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
  '/MVRCHPINFF_1.0/MVRRecLoop'
  passing xmltype(m.vendor_xml)
  columns J_SVCDesc varchar2(50) path 'HIJLoop/JRec/J_SVCDesc',
    xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x

在 CTE 中使用示例数据进行演示:

with mvr_dtl (vendor_xml) as (
  select to_clob('<MVRCHPINFF_1.0>
   <Routing ReplyToQMgr="PQ21" ReplyToQ="A4218QA.BIZTALK.REPLY.REPORT.PROD" CorelId="712393102361590" MsgType="8" Expiry="-1" MsgID="201904051632015"></Routing>
   <MVRRecLoop>
      <CLoop>
         <CRec>
            <C_MVRNumberAddr>ROMAN GENERAL</C_MVRNumberAddr>
         </CRec>
         <CRec>
            <C_MVRNumberAddr>ROMAN ST</C_MVRNumberAddr>
         </CRec>
         <CRec>
            <C_MVRNumberAddr>ROMAN CITY, ROME 111111</C_MVRNumberAddr>
         </CRec>
      </CLoop>
      <HIJLoop>
         <JRec>
            <J_SVCDesc>MVR RECORD CLEAR</J_SVCDesc>
         </JRec>
      </HIJLoop>
      </MVRRecLoop>
</MVRCHPINFF_1.0>')
  from dual
)
select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
  '/MVRCHPINFF_1.0/MVRRecLoop'
  passing xmltype(m.vendor_xml)
  columns J_SVCDesc varchar2(50) path 'HIJLoop/JRec/J_SVCDesc',
    xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x;
J_SVCDESC                                          XMLDETAILS                                                                                                                                                                                              
-------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MVR RECORD CLEAR                                   ROMAN GENERAL|ROMAN ST|ROMAN CITY, ROME 111111                                                                                                                                                          

如果 HIJLoop 节点名称表明也可能有多个 JRec 值,那么您也可以将它们连接起来:

  columns J_SVCDesc varchar2(50) path 'string-join(HIJLoop/JRec/J_SVCDesc, "|")',
    xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'

这对示例 XML.

的输出没有影响

db<>fiddle


顺便说一句,你的第二次尝试成功了;它没有错误,但也没有得到正确的结果。你传递的 address 是一个只有兄弟节点的 XML 片段,而字符串连接只看到一个值,由那些 text() 组成(我认为......类似的东西).如果您改为向下传递 CLoop 并展开第二个 XPath,那么它会起作用:

select x1.j_svcdesc, x2.xmldetails
from mvr_dtl m
cross join xmltable (
  '/MVRCHPINFF_1.0/MVRRecLoop'
  passing xmltype(m.vendor_xml)
  columns J_SVCDesc varchar(50) path 'HIJLoop/JRec/J_SVCDesc',
    HIJLoop xmltype path 'CLoop'
) x1
cross join xmltable (
  'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
  passing x1.HIJLoop
  columns xmldetails varchar2(200) path '.'
) x2;

db<>fiddle

但是如果你真的得到 "ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence" 那么我怀疑你的数据实际上有多个 JRec 节点;在这种情况下,请参阅上面的第二个查询。

db<>fiddle 显示了这种方法和我的第一个查询的问题;它与我的第二个查询一起使用。所以你可能需要使用它:

select x.j_svcdesc, x.xmldetails
from mvr_dtl m
cross join xmltable (
  '/MVRCHPINFF_1.0/MVRRecLoop'
  passing xmltype(m.vendor_xml)
  columns J_SVCDesc varchar2(50) path 'string-join(HIJLoop/JRec/J_SVCDesc, "|")',
    xmldetails varchar2(200) path 'string-join(CLoop/CRec/C_MVRNumberAddr, "|")'
) x;

您可能还需要增加返回的列大小。