XML 数据作为历史记录
XML data as history of records
我在 SQL 服务器中有一个 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>
试试这个。
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)
或者,类似这样的事情——查询所有 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 服务器中有一个 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>
试试这个。
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)
或者,类似这样的事情——查询所有 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)