比较数据库中的 XML 值适用于更改但不适用于添加
Comparing XML values in database works for changes but not additions
我正在尝试比较 XML 数据以确定已更改或添加的内容。如果更改了单个记录,或者以相同的顺序发生了多个更改,则它 returns 是预期的结果。但是,如果添加了新记录,它不会按预期工作。
我遇到的问题是数据可能来自许多地方,因此数据中没有一致的 table 名称、ID 或其他内容。然而 XML 将始终有一个 <original>
和 <changed>
节点,其中将包含查询结果,如下所示:
@xmlOriginal =SELECT * FROM Table WHERE ID=@ID FOR XML AUTO, ELEMENTS XSINIL, ROOT('Original'))
--INSERT query goes here
@xmlChanged = SELECT * FROM TABLE WHERE ID=@ID FOR XML AUTO, ELEMENTS XSINIL, ROOT('Changed'))
SET @xml = (SELECT @xmlOriginal, @xmlChanged for XML Path('Update'))
有没有办法智能地找出什么是 changed/added?我只需要知道原始值与新值,不管是否有原始值。
我在下面创建了一个简单示例,该示例从一行开始,然后添加另一行。当我运行 我的SQL 看到变化时,它显示了错误的信息。为了清楚起见,我也包括了实际和期望的结果。
DECLARE @Audit TABLE (
id int not null,
Details xml
)
INSERT INTO @Audit (ID,details)
Values (1,
'<Update>
<Original xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dbo.MyTable>
<ID>E99C0245-1A06-EA11-A836-00155DB6D822</ID>
<Amount>1234.00</Amount>
</dbo.MyTable>
</Original>
<Changed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dbo.MyTable>
<ID>E99C0245-1A06-EA11-A836-00155DB6D822</ID>
<Amount>1234.00</Amount>
</dbo.MyTable>
<dbo.MyTable>
<ID>D74B6DED-1B06-EA11-A836-00155DB6D822</ID>
<Amount>555.00</Amount>
</dbo.MyTable>
</Changed>
</Update>')
DECLARE @XML XML = (SELECT Details FROM @Audit WHERE ID = 1)
;WITH
XMLOriginal AS
(
SELECT T.N.value('local-name(.)', 'nvarchar(100)') as Field,
T.N.value('.', 'nvarchar(1000)') as VALUE
FROM @XML.nodes('Update/Original/*/*') as T(N)
),
XMLChanged as
(
SELECT T.N.value('local-name(.)', 'nvarchar(100)') as Field,
T.N.value('.', 'nvarchar(1000)') as VALUE
FROM @XML.nodes('Update/Changed/*/*') as T(N)
)
SELECT
COALESCE(XMLOriginal.Field, XMLChanged.Field) as Field
,XMLOriginal.VALUE as Original
,XMLChanged.VALUE as Changed
FROM
XMLOriginal
FULL OUTER JOIN XMLChanged
ON XMLOriginal.Field = XMLChanged.Field
LEFT OUTER JOIN @Audit L
ON L.ID = 1
WHERE COALESCE(XMLOriginal.VALUE, '') <> COALESCE(XMLChanged.VALUE, '')
输出:
+--------+--------------------------------------+--------------------------------------+
| FIELD | ORIGINAL | CHANGED |
+--------+--------------------------------------+--------------------------------------+
| Amount | 1234.00 | 555.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | E99C0245-1A06-EA11-A836-00155DB6D822 | D74B6DED-1B06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
期望的输出:
+--------+--------------------------------------+--------------------------------------+
| FIELD | ORIGINAL | CHANGED |
+--------+--------------------------------------+--------------------------------------+
| Amount | 1234.00 | 1234.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | E99C0245-1A06-EA11-A836-00155DB6D822 | E99C0245-1A06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
| Amount | NULL | 555.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | NULL | D74B6DED-1B06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
我认为你很接近——根据我的经验,很难使用完全外部连接并获得有用的结果——我喜欢只使用左连接并使用一组已知的键连接到两侧。 .. 像这样(考虑到您的 CTE)
SELECT BASE.Field,
O.VALUE AS Original_Value
C.VALUE AS Changed_Value
FROM (SELECT Field FROM XMLOriginal
UNION
SELECT Field FROM XMLChanged) AS BASE
LEFT JOIN XMLOriginal AS O ON BASE.Field = O.Field
LEFT JOIN XMLChanged AS C ON BASE.Field = C.Field
我正在尝试比较 XML 数据以确定已更改或添加的内容。如果更改了单个记录,或者以相同的顺序发生了多个更改,则它 returns 是预期的结果。但是,如果添加了新记录,它不会按预期工作。
我遇到的问题是数据可能来自许多地方,因此数据中没有一致的 table 名称、ID 或其他内容。然而 XML 将始终有一个 <original>
和 <changed>
节点,其中将包含查询结果,如下所示:
@xmlOriginal =SELECT * FROM Table WHERE ID=@ID FOR XML AUTO, ELEMENTS XSINIL, ROOT('Original'))
--INSERT query goes here
@xmlChanged = SELECT * FROM TABLE WHERE ID=@ID FOR XML AUTO, ELEMENTS XSINIL, ROOT('Changed'))
SET @xml = (SELECT @xmlOriginal, @xmlChanged for XML Path('Update'))
有没有办法智能地找出什么是 changed/added?我只需要知道原始值与新值,不管是否有原始值。
我在下面创建了一个简单示例,该示例从一行开始,然后添加另一行。当我运行 我的SQL 看到变化时,它显示了错误的信息。为了清楚起见,我也包括了实际和期望的结果。
DECLARE @Audit TABLE (
id int not null,
Details xml
)
INSERT INTO @Audit (ID,details)
Values (1,
'<Update>
<Original xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dbo.MyTable>
<ID>E99C0245-1A06-EA11-A836-00155DB6D822</ID>
<Amount>1234.00</Amount>
</dbo.MyTable>
</Original>
<Changed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dbo.MyTable>
<ID>E99C0245-1A06-EA11-A836-00155DB6D822</ID>
<Amount>1234.00</Amount>
</dbo.MyTable>
<dbo.MyTable>
<ID>D74B6DED-1B06-EA11-A836-00155DB6D822</ID>
<Amount>555.00</Amount>
</dbo.MyTable>
</Changed>
</Update>')
DECLARE @XML XML = (SELECT Details FROM @Audit WHERE ID = 1)
;WITH
XMLOriginal AS
(
SELECT T.N.value('local-name(.)', 'nvarchar(100)') as Field,
T.N.value('.', 'nvarchar(1000)') as VALUE
FROM @XML.nodes('Update/Original/*/*') as T(N)
),
XMLChanged as
(
SELECT T.N.value('local-name(.)', 'nvarchar(100)') as Field,
T.N.value('.', 'nvarchar(1000)') as VALUE
FROM @XML.nodes('Update/Changed/*/*') as T(N)
)
SELECT
COALESCE(XMLOriginal.Field, XMLChanged.Field) as Field
,XMLOriginal.VALUE as Original
,XMLChanged.VALUE as Changed
FROM
XMLOriginal
FULL OUTER JOIN XMLChanged
ON XMLOriginal.Field = XMLChanged.Field
LEFT OUTER JOIN @Audit L
ON L.ID = 1
WHERE COALESCE(XMLOriginal.VALUE, '') <> COALESCE(XMLChanged.VALUE, '')
输出:
+--------+--------------------------------------+--------------------------------------+
| FIELD | ORIGINAL | CHANGED |
+--------+--------------------------------------+--------------------------------------+
| Amount | 1234.00 | 555.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | E99C0245-1A06-EA11-A836-00155DB6D822 | D74B6DED-1B06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
期望的输出:
+--------+--------------------------------------+--------------------------------------+
| FIELD | ORIGINAL | CHANGED |
+--------+--------------------------------------+--------------------------------------+
| Amount | 1234.00 | 1234.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | E99C0245-1A06-EA11-A836-00155DB6D822 | E99C0245-1A06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
| Amount | NULL | 555.00 |
+--------+--------------------------------------+--------------------------------------+
| ID | NULL | D74B6DED-1B06-EA11-A836-00155DB6D822 |
+--------+--------------------------------------+--------------------------------------+
我认为你很接近——根据我的经验,很难使用完全外部连接并获得有用的结果——我喜欢只使用左连接并使用一组已知的键连接到两侧。 .. 像这样(考虑到您的 CTE)
SELECT BASE.Field,
O.VALUE AS Original_Value
C.VALUE AS Changed_Value
FROM (SELECT Field FROM XMLOriginal
UNION
SELECT Field FROM XMLChanged) AS BASE
LEFT JOIN XMLOriginal AS O ON BASE.Field = O.Field
LEFT JOIN XMLChanged AS C ON BASE.Field = C.Field