1

我在触发器中捕获inserteddeleted表的内容并将它们作为 xml 保存到更改日志中。

对于直接插入和删除它。只需在对应表上进行选择并使用FOR XML将其转换为 xml。

更新变得有点棘手,因为您要合并两个表中的数据,这些基本上代表UPDATE. 现在我正在使用 aUNION将数据从inserteddeleted合并到一个结果集中。

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>

或者可能

<row>
    <Column1 Before="Foo" After="Bar" />
    <Column2 Before="Lorem" After="Ipsum" />
</row>

但我不确定如何做到这一点。有任何想法吗?

注意:我们的一些客户仍在使用 SQL Server 2005,因此使用新的更改跟踪确实不是一个选项。

4

3 回答 3

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')
于 2012-04-24T16:06:10.183 回答
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'
于 2012-04-24T16:57:21.643 回答
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
于 2012-04-24T16:07:02.857 回答