You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SQL的OPENXML中访问XML标签的相邻同级标签

解决OPENXML读取XML同级节点的问题

你的XML结构中,<ENVELOPE>下包含多组<BILLFIXED>及其同级的<BILLOP>、<BILLCL>、<BILLDUE>、<BILLOVERDUE>节点。使用OPENXML时,由于上下文定位在<BILLFIXED>节点内,无法直接访问同级节点,需要调整XPath路径来关联对应的节点组。

方法一:修正OPENXML的XPath路径

通过../回到父节点<ENVELOPE>,并利用position()函数匹配每个<BILLFIXED>对应的同级节点组,同时修正原代码中<BILLCL>的路径错误:

DECLARE @xml xml = '<ENVELOPE>
    <BILLFIXED>
        <BILLDATE>29-Jun-2019</BILLDATE>
        <BILLREF>123</BILLREF>
        <BILLPARTY>ABC</BILLPARTY>
    </BILLFIXED>
    <BILLOP>200</BILLOP>
    <BILLCL>200</BILLCL>
    <BILLDUE>29-Jun-2019</BILLDUE>
    <BILLOVERDUE>1116</BILLOVERDUE>
    <BILLFIXED>
        <BILLDATE>30-Jun-2019</BILLDATE>
        <BILLREF>April To June -19</BILLREF>
        <BILLPARTY>efg</BILLPARTY>
    </BILLFIXED>
    <BILLOP>100</BILLOP>
    <BILLCL>100</BILLCL>
    <BILLDUE>30-Jun-2019</BILLDUE>
    <BILLOVERDUE>1115</BILLOVERDUE>
</ENVELOPE>'

DECLARE @hDoc AS INT
EXEC sp_xml_preparedocument @hDoc OUTPUT, @xml 

SELECT  
    BILLDATE, 
    BILLREF, 
    BILLPARTY, 
    BILLOP,
    BILLCL,
    BILLDUE, 
    BILLOVERDUE
FROM OPENXML(@hDoc, '//BILLFIXED') 
WITH ( 
    BillDate [varchar](50) 'BILLDATE', 
    BIllREF [varchar](50) 'BILLREF', 
    BILLPARTY [varchar](100) 'BILLPARTY',
    -- 通过../访问父节点,并通过position()匹配对应位置的同级节点
    BILLOP [varchar](100) '../BILLOP[position()=count(../BILLFIXED[. current()]/preceding-sibling::BILLFIXED)+1]',
    BILLCL [varchar](100) '../BILLCL[position()=count(../BILLFIXED[. current()]/preceding-sibling::BILLFIXED)+1]',
    BILLDUE [varchar](100) '../BILLDUE[position()=count(../BILLFIXED[. current()]/preceding-sibling::BILLFIXED)+1]',
    BILLOVERDUE [varchar](100) '../BILLOVERDUE[position()=count(../BILLFIXED[. current()]/preceding-sibling::BILLFIXED)+1]'
) 

EXEC sp_xml_removedocument @hDoc

说明:count(../BILLFIXED[. current()]/preceding-sibling::BILLFIXED)+1用于计算当前<BILLFIXED>的位置,确保匹配对应顺序的<BILLOP>等节点组。

方法二:使用XQuery(推荐)

相较于OPENXML,XQuery更直观且性能更优,通过给每个<BILLFIXED>分配索引,匹配对应位置的同级节点:

DECLARE @xml xml = '<ENVELOPE>
    <BILLFIXED>
        <BILLDATE>29-Jun-2019</BILLDATE>
        <BILLREF>123</BILLREF>
        <BILLPARTY>ABC</BILLPARTY>
    </BILLFIXED>
    <BILLOP>200</BILLOP>
    <BILLCL>200</BILLCL>
    <BILLDUE>29-Jun-2019</BILLDUE>
    <BILLOVERDUE>1116</BILLOVERDUE>
    <BILLFIXED>
        <BILLDATE>30-Jun-2019</BILLDATE>
        <BILLREF>April To June -19</BILLREF>
        <BILLPARTY>efg</BILLPARTY>
    </BILLFIXED>
    <BILLOP>100</BILLOP>
    <BILLCL>100</BILLCL>
    <BILLDUE>30-Jun-2019</BILLDUE>
    <BILLOVERDUE>1115</BILLOVERDUE>
</ENVELOPE>'

SELECT
    billFixed.value('(BILLDATE/text())[1]', 'varchar(50)') AS BILLDATE,
    billFixed.value('(BILLREF/text())[1]', 'varchar(50)') AS BILLREF,
    billFixed.value('(BILLPARTY/text())[1]', 'varchar(100)') AS BILLPARTY,
    @xml.value('(ENVELOPE/BILLOP[position() = sql:column("idx")]/text())[1]', 'varchar(100)') AS BILLOP,
    @xml.value('(ENVELOPE/BILLCL[position() = sql:column("idx")]/text())[1]', 'varchar(100)') AS BILLCL,
    @xml.value('(ENVELOPE/BILLDUE[position() = sql:column("idx")]/text())[1]', 'varchar(100)') AS BILLDUE,
    @xml.value('(ENVELOPE/BILLOVERDUE[position() = sql:column("idx")]/text())[1]', 'varchar(100)') AS BILLOVERDUE
FROM (
    -- 为每个BILLFIXED生成索引,对应同级节点组的位置
    SELECT
        billFixed.query('.') AS billFixed,
        ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS idx
    FROM @xml.nodes('/ENVELOPE/BILLFIXED') AS bf(billFixed)
) AS subQuery

说明:子查询中用ROW_NUMBER()给每个<BILLFIXED>分配顺序索引,主查询通过该索引匹配对应位置的<BILLOP>等节点,确保数据关联正确。

内容的提问来源于stack exchange,提问作者rajsx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 18:16:03