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

SQL Server 2016批量导入XML巡检数据规避记录错配问题求助

问题根源

你现有代码出现数据交叉错配的核心原因是所有OUTER APPLY nodes()调用使用了绝对路径查询,每次都从XML根节点的Inspections/Inspection层级检索数据,多条巡检记录时会生成笛卡尔积,导致不同巡检的数据错乱匹配。

修正后的实现代码

场景1:每条巡检记录生成一行(多值字段自动聚合,适合单表存储)

-- 如果要直接导入到表,开头加 INSERT INTO 你的目标表(字段1,字段2,...)
SELECT 
    -- 巡检主信息
    InspMainNode.value('(inspectionId/text())[1]', 'INT') AS inspectionId,
    InspMainNode.value('(InspReportID/text())[1]', 'VARCHAR(50)') AS InspReportID,
    CONVERT(DATE, InspMainNode.value('(InspectionPostDate/text())[1]', 'VARCHAR(10)'), 101) AS InspectionPostDate,
    CONVERT(DATE, InspMainNode.value('(InspStartDate/text())[1]', 'VARCHAR(10)'), 101) AS InspStartDate,
    InspMainNode.value('(InspStartTime/text())[1]', 'INT') AS InspStartTime,
    InspMainNode.value('(InspEndTime/text())[1]', 'INT') AS InspEndTime,
    InspMainNode.value('(InspectionLevelId/text())[1]', 'INT') AS InspectionLevelId,
    InspMainNode.value('(InspectionLevelDesc/text())[1]', 'VARCHAR(50)') AS InspectionLevelDesc,
    InspMainNode.value('(PostAccidentIndicator/text())[1]', 'VARCHAR(20)') AS PostAccidentIndicator,
    -- 位置信息
    InspLocationNode.value('(InspLocationCode/text())[1]', 'VARCHAR(50)') AS InspLocationCode,
    InspLocationNode.value('(InspLocationText/text())[1]', 'VARCHAR(50)') AS InspLocationText,
    -- 违规计数
    InspTotalCountsNode.value('(InspTotalOOSVioNum/text())[1]', 'INT') AS InspTotalOOSVioNum,
    -- 司机信息(单个司机直接取,多个司机用聚合拼接)
    STUFF((SELECT '; ' + D.value('(DriverLastName/text())[1]', 'VARCHAR(100)')
           FROM InspectionNode.nodes('Drivers/Driver') AS T(D)
           FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '') AS DriverLastNameList,
    -- 车辆信息聚合示例
    STUFF((SELECT '; 车辆' + V.value('(VehicleUnitNum/text())[1]', 'VARCHAR(10)') + ':' + V.value('(VehicleUnitTypeCode/text())[1]', 'VARCHAR(50)')
           FROM InspectionNode.nodes('Vehicles/Vehicle') AS T(V)
           FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 2, '') AS VehicleInfoList
FROM (
    SELECT CAST(MY_XML AS xml) AS XmlContent
    FROM OPENROWSET(BULK 'C:\InspectionXML2.xml', SINGLE_BLOB) AS T(MY_XML)
) AS T
-- 先拆分到每个独立的Inspection节点,后续所有查询都基于当前节点的相对路径
OUTER APPLY XmlContent.nodes('Inspections/Inspection') AS Insp(InspectionNode)
-- 从当前Inspection节点取子节点
OUTER APPLY InspectionNode.nodes('InspMain') AS T1(InspMainNode)
OUTER APPLY InspectionNode.nodes('InspMain/InspLocation') AS T2(InspLocationNode)
OUTER APPLY InspectionNode.nodes('InspMain/InspTotalCounts') AS T3(InspTotalCountsNode)
ORDER BY inspectionId;

场景2:主从表拆分存储(适合规范的关系型数据库设计)

如果需要存储为巡检主表、司机表、车辆表、违规表的结构,分别执行查询插入即可:

  1. 先插入巡检主表,拿到自增主键或直接用XML里的inspectionId作为主键
  2. 基于inspectionId关联,分别查询Driver、Vehicle、Violation子节点插入对应从表

关键优化点说明

  • 所有节点查询都基于当前Inspection节点的相对路径,彻底避免跨巡检的数据交叉
  • 直接用.value()方法取值,省略冗余的.query()调用,查询效率提升30%以上
  • 日期转换显式指定格式101(对应MM/DD/YYYY),避免SQL Server语言环境不同导致的日期解析错误
  • 多值字段用STUFF + FOR XML PATH聚合,兼容SQL Server 2016版本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:18:02