【问题标题】:SQL XML Parsing in T-SQLT-SQL 中的 SQL XML 解析
【发布时间】:2015-03-06 13:34:16
【问题描述】:

我有一个 SQL Server 表,它的 XML 列具有如下数据。表中将有多个记录。 让我们说表 T1 和列 C1。

我们的要求是我们需要获取最新数据(对于 AAA、BB、CC 等各个部分,按 datereported、datecreated、dateupdated XML 节点的最大值)。

<XMLDoc>
    <AAA>
      <Name>Name_A</Name>
      <Value>Val_A</Value>
      <dateReported>1/1/2001</dateReported>
    </AAA>
    <AAA>
      <Name>Name_B</Name>
      <Value>Val_B</Value>
      <dateReported>1/1/2014</dateReported>
    </AAA>
    <AAA>
      <Name>Name_C</Name>
      <Value>Val_C</Value>
      <dateReported>1/1/2012</dateReported>
    </AAA>
    <AAA>
      <Name>Name_D</Name>
      <Value>Val_D</Value>
      <dateReported>1/1/2011</dateReported>
    </AAA>
    <BB>
        <ID>112</ID>
        <dateCreated>1/1/2011</dateCreated>

    </BB>
        <BB>
        <ID>121</ID>
        <dateCreated>1/1/2012</dateCreated>
    </BB>
    <BB>
        <ID>12</ID>
        <dateCreated>1/1/2015</dateCreated>
    </BB>
    <CC>
        <Type>XML</Type>
        <dateUpdated>1/1/2015</dateCreated>
    </CC>
     <CC>
        <Type>TXT</Type>
        <dateUpdated>3/3/2015</dateUpdated>
    </CC>
     <CC>
        <Type>XLS</Type>
        <dateUpdated>2/2/2015</dateUpdated>
    </CC>
</XMLDoc>

我在下面写了 SQL

SELECT
        ID,
        Name = C1.value('(/XMLDoc/AAA/Name)[1]', 'varchar(100)'),
        Value = C1.value('(/XMLDoc/AAA/Value)[1]', 'varchar(100)'),
        BB_ID = C1.value('(/XMLDoc/BB/ID)[1]', 'int'), 
        CC_Type = C1.value('(/XMLDoc/CC/Type)[1]', 'varchar(50)')
From T1

我们需要输出为

Id Name, Value, BB_ID, CC_Type
1  Name_B Val_B  12    TXT

需要您的意见

【问题讨论】:

    标签: sql sql-server sql-server-2012 sqlxml


    【解决方案1】:

    您的 XML 示例大错特错 - 很多结束标签并不是真正的结束标签,有几个与开始标签不匹配,而且中间有一个 &lt;/x&gt;,没有任何开始标签...... ...下次,请确保您发布的内容是实际有效的 XML!

    试试这个代码:

    DECLARE @T1 TABLE (ID INT NOT NULL, XmlContent XML)
    
    INSERT INTO @T1 VALUES(1, '<XMLDoc>
        <AAA>
          <Name>Name_A</Name>
          <Value>Val_A</Value>
          <dateReported>1/1/2001</dateReported>
        </AAA>
        <AAA>
          <Name>Name_B</Name>
          <Value>Val_B</Value>
          <dateReported>1/1/2014</dateReported>
        </AAA>
        <AAA>
          <Name>Name_C</Name>
          <Value>Val_C</Value>
          <dateReported>1/1/2012</dateReported>
        </AAA>
        <AAA>
          <Name>Name_D</Name>
          <Value>Val_D</Value>
          <dateReported>1/1/2011</dateReported>
        </AAA>
        <BB>
            <ID>112</ID>
            <dateCreated>1/1/2011</dateCreated>
        </BB>
        <BB>
            <ID>121</ID>
            <dateCreated>1/1/2012</dateCreated>
        </BB>
        <BB>
            <ID>12</ID>
            <dateCreated>1/1/2015</dateCreated>
        </BB>
        <CC>
            <Type>XML</Type>
            <dateUpdated>1/1/2015</dateUpdated>
        </CC>
         <CC>
            <Type>TXT</Type>
            <dateUpdated>3/3/2015</dateUpdated>
        </CC>
         <CC>
            <Type>XLS</Type>
            <dateUpdated>2/2/2015</dateUpdated>
        </CC>
    </XMLDoc>')
    
    ;WITH XmlData AS
    (
        SELECT 
            ID,
            NodeType = 'AAA',
            RelevantDate = XC.value('(dateReported)[1]', 'datetime'),
            Name = XC.value('(Name)[1]', 'varchar(50)'),
            Value = XC.value('(Value)[1]', 'varchar(50)')
        FROM 
            @T1
        CROSS APPLY
            XmlContent.nodes('/XMLDoc/AAA') XT(XC)
    
        UNION
    
        SELECT 
            ID,
            NodeType = 'BB',
            RelevantDate = XC.value('(dateCreated)[1]', 'datetime'),
            Name = null,
            Value = XC.value('(ID)[1]', 'varchar(50)')
        FROM 
            @T1
        CROSS APPLY
            XmlContent.nodes('/XMLDoc/BB') XT(XC)
    
        UNION
    
        SELECT 
            ID,
            NodeType = 'CC',
            RelevantDate = XC.value('(dateUpdated)[1]', 'datetime'),
            Name = XC.value('(Type)[1]', 'varchar(50)'),
            Value = null
        FROM 
            @T1
        CROSS APPLY
            XmlContent.nodes('/XMLDoc/CC') XT(XC)
    )
    SELECT 
        xd.ID,
        Name = MAX(Name),
        Value = MAX(Value),
        BB_ID = MAX(BB_ID),
        CC_Type = MAX(CC_Type)
    FROM 
        XmlData xd
    WHERE
        xd.RelevantDate = (SELECT MAX(xd1.RelevantDate) FROM XmlData xd1 WHERE xd1.NodeType = xd.NodeType)
    GROUP BY
        xd.ID
    

    这给了我以下输出:

    基本上,使用您的 XML,我正在创建一个 CTE(公用表表达式),它为每个“节点类型”提取相关信息 - &lt;AAA&gt; 节点、&lt;BB&gt;&lt;CC&gt; 节点.然后,我可以通过从该 CTE 中进行选择来获取每个组的日期的 MAX()

    【讨论】:

    • 抱歉下次会处理的。你的输出不匹配..我需要最大日期值的数据节点,而查询只给出最大日期值
    • 谢谢,但是这个查询给出了 3 行,我希望输出为单行 Id Name, Value, BB_ID, CC_Type 1 Name_B Val_B 12 TXT
    • @Saravanan:更新了我的回复再次 - this 现在是否符合您的需求?
    【解决方案2】:

    我在网上搜索并找到了处理最大值的好方法:

    这是我使用的表格: CREATE TABLE #xmlTable (ID INT, xmlData XML)

    选择:

    SELECT 
        ID
        , xmlData.value ('(/XMLDoc/AAA[not(/XMLDoc/AAA/dateReported > dateReported)]/Name)[1]', 'varchar(100)') AS Name
        , xmlData.value ('(/XMLDoc/AAA[not(/XMLDoc/AAA/dateReported > dateReported)]/Value)[1]', 'varchar(100)') AS Value
        , xmlData.value ('(/XMLDoc/BB[not(/XMLDoc/BB/dateCreated > dateCreated)]/ID)[1]', 'INT') AS BB_ID
        , xmlData.value ('(/XMLDoc/CC[not(/XMLDoc/CC/dateUpdated > dateUpdated)]/Type)[1]', 'varchar(50)') AS CC_Type
    FROM #xmlTable AS xt
    

    最后的结果:

    ID  Name    Value   BB_ID   CC_Type  
    1   Name_B  Val_B   121     TXT
    

    我在这个例子中找到的解决方案https://stackoverflow.com/a/3786761/1692632

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      相关资源
      最近更新 更多