我正在捕获触发器中inserted
和deleted
表的内容,并将它们作为xml保存到更改日志中。
对于插入和删除它是直接的。只需在相应的表上进行选择,然后使用FOR XML
将其转换为xml。
更新变得有点棘手,因为您正在合并来自两个表的数据,这两个表基本上代表之前的和之后的状态{{1 }}。现在,我正在使用UPDATE
将UNION
和inserted
中的数据合并到一个结果集中。
deleted
输出类似于:
SELECT [Column1], [Column2]
FROM
(SELECT [Column1], [Column2]
FROM inserted
UNION
SELECT [Column], [Column2]
FROM deleted) as Rows
FOR XML RAW, ELEMENTS
我希望输出的是:
<!-- Comments added for clarity. They don't appear in the actual output -->
<row> <!-- After -->
<Column1>Bar</Column1>
<Column2>Ipsum</Column2>
</row>
<row> <!-- Before -->
<Column1>Foo</Column1>
<Column2>Lorem</Column2>
</row>
或者
<row>
<Column1>
<Before>Foo</Before>
<After>Bar</After>
</Column1>
<Column2>
<Before>Lorem</Before>
<After>Ipsum</After>
</Column2>
</row>
但我不知道如何做到这一点。有什么想法吗?
注意:我们的一些客户仍在使用SQL Server 2005,因此使用新的更改跟踪确实不是一个选项。
答案 0 :(得分:2)
你可以试试这个。我已使用常规表(不在触发器中)进行测试。并假设PK被称为ID
。
select d.Column1 as 'Column1/Before',
i.Column1 as 'Column1/After',
d.Column2 as 'Column2/Before',
i.Column2 as 'Column2/After'
from inserted as i
inner join deleted as d
on i.ID = d.ID
for xml path('row')
答案 1 :(得分:2)
我已经完成了这个审计跟踪解决方案,并遇到了同样的问题。我的决议如下:
正如您所提到的,插入和删除很容易。插入新记录时,我们不存储任何XML,因为插入中包含的字段值是实时表中的当前值。删除记录时,将记录的状态存储在XML字段中删除的位置。
更新带来了一些问题,因为我不想为每条记录(即之前和之后)存储两次数据。然后我发现我只需要存储“Before”数据(即删除的表),因为“After”存储在原始表本身中,或者下面的审计跟踪记录存储在同一记录中。它在重建路径时确实让生活变得更加困难,但从存储的角度来看确实有意义。
换句话说,假设在01:00:00添加了一条记录。记录在02:00:00和02:30:00更新,并在03:00:00删除。您的审计跟踪看起来像:
AuditKey Timestamp RecordType RecordKey AuditType XML
1 01:00:00 MyTable 213 I NULL
2 02:00:00 MyTable 213 U XML1
3 02:30:00 MyTable 213 U XML2
4 03:00:00 MyTable 213 D XML3
使用自联接,您可以获得两个连续记录,显示MyTable中记录的前后状态。我们的样本记录的审计跟踪如下:
From AuditKey 1 and 2: Record was inserted at 01:00, with the field values XML1
From AuditKey 2 and 3: Record was updated at 02:00, and changed from XML1 to XML2
From AuditKey 3 and 4: Record was updated at 02:30, and changed from XML2 to XML3
From AuditKey 4 and NULL: Record was deleted at 03:00
如果最后一条记录不是删除,而是另一条更新,那么审计跟踪的最后一行会显示为:
From AuditKey 4 and NULL: Record was updated at 03:00, and changed from XML3 to the field values in the live table.
这种方法对我们来说效果很好,我们能够将记录重建到历史的任何一点。进一步采用这种方法,针对每条记录存储的XML仅记录其值已更改的字段。这意味着我们无法立即确定历史中两点之间的更改,而无需迭代其间的所有日志。但是,由于这些日志很少被查看,因此优先考虑使它们高效而不是快速。这取决于您特定环境的要求。
我使用的查询示例如下所示:
WITH cte AS (SELECT ROW_NUMBER() OVER (ORDER BY [Timestamp]) AS RowNum,
AuditKey, [Timestamp], AuditType, XML FROM AuditTrail
WHERE RecordType = 'MyTable' AND RecordKey = 213)
SELECT t1.Timestamp, t1.AuditType, t1.XML AS FromXML,
CASE WHEN t2.XML IS NULL THEN (SELECT * FROM MyTable WHERE RecordKey = 213 FOR XML AUTO) ELSE t2.XML END AS ToXML
FROM cte t1 LEFT JOIN cte t2 ON t2.AuditKey = t1.AuditKey + 1
WHERE t2.AuditType <> 'D'
答案 2 :(得分:1)
SELECT CAST('
<row>
<Column1 Before="' + i.Column1 + '" After="' + d.Column1 + '" />
<Column2 Before="' + i.Column2 + '" After="' + d.Column2 + '" />
</row>' AS xml)
FROM inserted i
INNER JOIN deleted d ON i.ID = d.ID