【问题标题】:XML data as history of recordsXML 数据作为记录的历史
【发布时间】:2015-01-11 16:44:21
【问题描述】:

我在 SQL Server 中有一个 XML 列,用于存储属性的实际值和前一个值。 例如。名称

<attribute name="Name">
      <actuals>
          <element isPreferred="true" name="FirstName">Name 2</element>
          <element isPreferred="false" name="LastName">N2</element>
       </actuals>
      <previous>
          <element isPreferred="true" name="FirstName">Name 1</element>
          <element isPreferred="false" name="LastName">N1</element>
      </previous>
</attribute>

如何显示属性的历史记录

------------------------------------
Attribute | New Value | OldValue
------------------------------------
First Name| Name2     | Name1
Last Name | N2        | N1
------------------------------------

属性可能会有所不同,可以包含单个元素,例如性别,也可以包含多个元素,例如姓名或地址(addressLine1、城市、州、国家/地区)

<attribute name="Gender">
      <actuals>
          <element isPreferred="true" name="Gender">Male</element>             
       </actuals>
      <previous>
          <element isPreferred="true" name="Gender">Other</element>     
      </previous>
</attribute>

【问题讨论】:

    标签: sql sql-server xml xquery sqlxml


    【解决方案1】:

    试试这个。

    DECLARE @xml1 XML='<attribute name="Name">
          <actuals>
              <element isPreferred="true" name="FirstName">Name 2</element>
              <element isPreferred="false" name="LastName">N2</element>
           </actuals>
          <previous>
              <element isPreferred="true" name="FirstName">Name 1</element>
              <element isPreferred="false" name="LastName">N1</element>
          </previous>
    </attribute>'
    
    SELECT Attribute=[Xml_Tab].[Cols].value('(actuals/element/@name)[1]', 'varchar(50)'),
           [New Value]=[Xml_Tab].[Cols].value('(actuals/element)[1]', 'varchar(50)'),
           OldValue=[Xml_Tab].[Cols].value('(previous/element)[1]', 'varchar(50)')
    FROM   @xml1.nodes('/attribute')AS [Xml_Tab]([Cols])
    UNION
    SELECT [Xml_Tab].[Cols].value('(actuals/element/@name)[2]', 'varchar(50)'),
           [Xml_Tab].[Cols].value('(actuals/element)[2]', 'varchar(50)'),
           [Xml_Tab].[Cols].value('(previous/element)[2]', 'varchar(50)')
    FROM   @xml1.nodes('/attribute')AS [Xml_Tab]([Cols]) 
    

    【讨论】:

    • 谢谢,它适用于名称,但属性可能有多个元素,如地址(addressLiine1,城市,州,国家)
    【解决方案2】:

    您可以查询实际和以前的节点,然后像这样加入它们:

    ;with cte_act as (
        select
            t.c.value('@name', 'nvarchar(128)') as [Attribute],
            t.c.value('.', 'nvarchar(128)') as [Value]
        from @data.nodes('/attribute/actuals/element') as t(c)
    ), cte_prev as (
        select
            t.c.value('@name', 'nvarchar(128)') as [Attribute],
            t.c.value('.', 'nvarchar(128)') as [Value]
        from @data.nodes('/attribute/previous/element') as t(c)
    )
    select
        act.[Attribute],
        act.[Value] as [New Value],
        prev.[Value] as [Old Value]
    from cte_act as act
        left outer join cte_prev as prev on prev.[Attribute] = act.[Attribute]
    

    sql fiddle demo

    或者你可以做一些疯狂的事情,比如用 xquery 重新格式化你的 xml 然后查询它:

    ;with cte as (
        select
            t.c.query('
                for $act in actuals/element
                    return <element name="{$act/@name}" newvalue="{$act/text()}" oldvalue="{($act/../../previous/element[@name=$act/@name])[1]/text()}"/>
            ') as data
        from <your table> as d
            outer apply d.data.nodes('/attribute') as t(c)
    )
    select
        t.c.value('@name', 'nvarchar(128)') as [Attribute],
        t.c.value('@newvalue', 'nvarchar(128)') as [New Value],
        t.c.value('@oldvalue', 'nvarchar(128)') as [Old Value]
    from cte as d
        outer apply data.nodes('element') as t(c)
    

    sql fiddle demo

    或者,像这样 - 查询所有 actual 元素并为每个实际元素尝试获取 previous

    select
        t.c.value('@name', 'nvarchar(128)') as [Attribute],
        t.c.value('.', 'nvarchar(128)') as [Value],
        t.c.value('let $name:=@name return (../../previous/element[@name=$name])[1]', 'nvarchar(128)') as [Value]
    from @temp as d
        outer apply d.data.nodes('/attribute/actuals/element') as t(c)
    

    sql fiddle demo

    【讨论】:

    • 谢谢罗曼。您能否从性能的角度提出最佳方法?
    • @BijuThomas 我建议使用最后一个,但最好在您的数据上进行测试
    猜你喜欢
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    相关资源
    最近更新 更多