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

SQL Server中如何用单查询拆分多层节点XML?求助解决方案

拆分SQL Server中多层级XML的单个查询方案

这个多层级XML的拆分确实有点绕,但用SQL Server自带的XML数据类型方法完全可以通过单个查询搞定。我结合你给出的XML结构,写个具体的示例一步步拆解:

首先,假设你的XML内容是存储在变量里的(如果是表列的话,只需要替换成表列即可):

DECLARE @xml XML = '<Report>
  <P>
    <Data>
      <Cust custID = "A" custName = "B" ></Cust>
    </Data>
  </P>
  <H>
    <Data1>
      <Seats>
        <Seat id = "abc" value = "123" ></Seat>
        <Date depart = "abc1" arrive = "1231" ></Date>
      </Seats>
      <Records>
        <Record recID = "C" col2 = "D" ></Record>
        <Record recID = "E" col2 = "F" ></Record>
      </Records>
    </Data1>
  </H>
</Report>';

SELECT
  -- 提取P节点下的客户属性
  Cust.value('@custID', 'VARCHAR(50)') AS CustID,
  Cust.value('@custName', 'VARCHAR(50)') AS CustName,
  -- 提取Seats节点下的座位信息
  Seat.value('@id', 'VARCHAR(50)') AS SeatID,
  Seat.value('@value', 'VARCHAR(50)') AS SeatValue,
  -- 提取Seats节点下的日期信息
  DepartDate.value('@depart', 'VARCHAR(50)') AS DepartDate,
  DepartDate.value('@arrive', 'VARCHAR(50)') AS ArriveDate,
  -- 提取Records节点下的记录信息
  Record.value('@recID', 'VARCHAR(50)') AS RecID,
  Record.value('@col2', 'VARCHAR(50)') AS Col2
FROM
  @xml.nodes('/Report') AS Report(Rpt)
-- 关联P层级的客户节点
CROSS APPLY
  Rpt.nodes('P/Data/Cust') AS PData(Cust)
-- 关联H层级的座位节点
CROSS APPLY
  Rpt.nodes('H/Data1/Seats/Seat') AS Seats(Seat)
-- 关联H层级的日期节点
CROSS APPLY
  Rpt.nodes('H/Data1/Seats/Date') AS Dates(DepartDate)
-- 关联H层级的记录节点
CROSS APPLY
  Rpt.nodes('H/Data1/Records/Record') AS Records(Record);

关键逻辑说明:

  • .nodes()方法用来定位XML中的目标节点,返回一个包含节点行的结果集;
  • CROSS APPLY用来逐层关联子节点,相当于把每个层级的节点进行笛卡尔积组合,确保所有层级的信息都能关联输出;
  • .value()方法负责提取节点的属性值,第一个参数是属性的XPath路径(@属性名表示取节点属性),第二个参数是转换后的SQL数据类型。

适配表列场景

如果你的XML是存储在表的列中(比如表名为ReportTable,XML列名为ReportXML),只需要把变量替换成表列即可:

SELECT
  Cust.value('@custID', 'VARCHAR(50)') AS CustID,
  Cust.value('@custName', 'VARCHAR(50)') AS CustName,
  Seat.value('@id', 'VARCHAR(50)') AS SeatID,
  Seat.value('@value', 'VARCHAR(50)') AS SeatValue,
  DepartDate.value('@depart', 'VARCHAR(50)') AS DepartDate,
  DepartDate.value('@arrive', 'VARCHAR(50)') AS ArriveDate,
  Record.value('@recID', 'VARCHAR(50)') AS RecID,
  Record.value('@col2', 'VARCHAR(50)') AS Col2
FROM
  ReportTable
CROSS APPLY
  ReportXML.nodes('/Report/P/Data/Cust') AS PData(Cust)
CROSS APPLY
  ReportXML.nodes('/Report/H/Data1/Seats/Seat') AS Seats(Seat)
CROSS APPLY
  ReportXML.nodes('/Report/H/Data1/Seats/Date') AS Dates(DepartDate)
CROSS APPLY
  ReportXML.nodes('/Report/H/Data1/Records/Record') AS Records(Record);

可选优化:处理非必填节点

如果某些子节点可能不存在(比如部分Report没有Records),可以把CROSS APPLY换成OUTER APPLY,这样即使子节点缺失,上层的信息依然会保留,缺失字段会显示为NULL。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:21:23