【问题标题】:SQL XML parsing different nodesSQL XML解析不同节点
【发布时间】:2019-10-24 15:35:02
【问题描述】:

我想请你帮忙解析 SQL 中的 XML,我的 XML 看起来像这样,其中 Load 是可以重复 X 次的父项。我需要 Column SerNr 并且每一行都需要绑定订单名称 决赛桌看起来像这样

表格示例:

<ImageHistory>    
    <Load targets="2" totalTime="417">
    <Orders>
    <Order name="20548976"/>
    </Orders>
    <Data>
    <Disk SerNr="XXXXXX" Size_mb="228936" LoadSuccessfull="true" /> 
    <Disk SerNr="ZZZZZ" Size_mb="228936" LoadSuccessfull="true" /> 
    </Data>
    </Load>
    </ImageHistory>

sql是

with data as (SELECT CAST(MY_XML AS xml) as MY_XML FROM OPENROWSET(BULK 'addres to xml', SINGLE_BLOB) AS T(MY_XML)), 
datainfo as (
SELECT
MY_XML.Blasting.value(' @name', 'BIGINT') as Size_mb,
MY_XML.Blasting.value('@SerNr', 'varchar(32)') as SerNr
FROM data CROSS APPLY MY_XML.nodes('ImageHistory/Load/Data/Disk') AS MY_XML (Blasting))
select * from datainfo 

谢谢你的帮助

【问题讨论】:

    标签: sql sql-server xml


    【解决方案1】:

    我将 XML 保存为文件系统上的文件:e:\Temp\DiskSerialNumbers.xml 其余的在下面。

    SQL

    ;WITH XmlFile (Contents) AS
    (
       SELECT CAST(BulkColumn AS XML) 
       FROM OPENROWSET(BULK 'e:\Temp\DiskSerialNumbers.xml', SINGLE_BLOB) AS XmlData
    )
    SELECT c.value('(../../Orders/Order/@name)[1]', 'INT') AS [Name]
        , c.value('@SerNr', 'VARCHAR(20)') AS [SerNr]
    FROM XmlFile CROSS APPLY Contents.nodes('/ImageHistory/Load/Data/Disk') AS t(c);
    

    输出

    +----------+--------+
    |   Name   | SerNr  |
    +----------+--------+
    | 20548976 | XXXXXX |
    | 20548976 | ZZZZZ  |
    +----------+--------+
    

    【讨论】:

    • 嗨 Yitzhak,我刚刚添加了一个替代方案,因为向后导航是性能杀手...
    • 嗨,Shnugo,很划算。我非常清楚向后 XPath 导航是性能杀手。提供的 XML 示例非常小,所以我没有费心使用两个 CROSS APPLY 子句...
    【解决方案2】:

    你已经有了答案,但我想指出一个事实,向后导航(使用../../)是horribly slow with bigger structures

    我建议这样做:

    模拟您的问题的模型

    DECLARE @yourTable TABLE(ID INT IDENTITY,YourXml XML);
    INSERT INTO @yourTable VALUES 
    (N'<ImageHistory>
        <Load targets="2" totalTime="417">
        <Orders>
            <Order name="20548976" />
        </Orders>
        <Data>
            <Disk SerNr="XXXXXX" Size_mb="228936" LoadSuccessfull="true" />
            <Disk SerNr="ZZZZZ" Size_mb="228936" LoadSuccessfull="true" />
        </Data>
        </Load>
    </ImageHistory>');
    

    --查询

    SELECT t.ID
            ,ld.value('@targets','int') AS Load_Targets
            ,ld.value('@totalTime','int') AS Load_TotalTime
            ,ld.value('(Orders/Order/@name)[1]','int') AS Order_Name
            ,dsk.value('@SerNr','nvarchar(100)') AS Disk_SerNr
            ,dsk.value('@Size_mb','nvarchar(100)') AS Disk_Size_mb
            ,dsk.value('@LoadSuccessfull','bit') AS Disk_LoadSuccessfull
    FROM @yourTable AS t
    CROSS APPLY t.YourXml.nodes('/ImageHistory/Load') A(ld)
    CROSS APPLY A.ld.nodes('Data/Disk') B(dsk); 
    

    简而言之:

    第一个APPLY 将下潜到&lt;Load&gt; 并将返回所有&lt;Load&gt; 元素(如果还有更多...

    第二个APPLY 将使用第一个APPLY 返回的片段并深入到&lt;Disk&gt;

    我们针对第一个片段(即&lt;Load&gt; 元素)调用.value() 获取订单名称(和其他值),并针对第二个@ 的片段调用.value() 获取&lt;Disk&gt; 的值987654335@。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多