Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql XML数据作为记录的历史记录_Sql_Sql Server_Xml_Xquery_Sqlxml - Fatal编程技术网

Sql XML数据作为记录的历史记录

Sql XML数据作为记录的历史记录,sql,sql-server,xml,xquery,sqlxml,Sql,Sql Server,Xml,Xquery,Sqlxml,我在SQLServer中有一个XML列,存储属性的实际值和前一个值。 姓名 <attribute name="Name"> <actuals> <element isPreferred="true" name="FirstName">Name 2</element> <element isPreferred="false" name="LastName">N2</element&

我在SQLServer中有一个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>
属性可能会有所不同,可以有单个元素(如性别)或多个元素(如名称或地址1、城市、州、国家)

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

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]) 

您可以查询实际节点和以前的节点,然后按如下方式连接它们:

;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]
或者您可以做一些疯狂的事情,比如用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)

谢谢,它适用于Name,但属性可能有多个元素,如addressliine1、city、state、country。从性能的角度来看,您能建议哪一种方法是最好的方法吗?@BijuThomas我建议使用最后一种方法,但最好在您的数据上进行测试
;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)
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)