将行标识为包含某些列中的更改的更改

时间:2011-02-23 20:08:07

标签: sql sql-server sql-server-2008 stored-procedures

在我们的业务规则中,我们需要跟踪何时指定一行被更改。该表包含根据我们的业务目的指定为不相关的多个列(例如输入日期字段,时间戳,查看位字段或接收位字段)。该表有很多列,我试图找到一种优雅的方法来确定是否有任何相关字段已更改,然后在审计表中记录一个条目(输入行的PK值 - 无法编辑PK)。我甚至不需要知道哪个列实际发生了变化(虽然它会在路上很好)。

我能够通过存储过程完成它,但它是一个丑陋的SP,使用以下语法进行更新(OR语句明显缩短为post):

INSERT INTO [TblSourceDataChange] (pkValue)
    SELECT d.pkValue
    FROM deleted d INNER JOIN inserted i ON d.pkValue=i.pkValue
    WHERE (    i.[F440] <> d.[F440]
          OR i.[F445] <> d.[F445]
          OR i.[F450] <> d.[F450])

我正在尝试找到一种通用方法,我可以指定忽略字段,即使我在表中添加了其他相关字段,存储过程仍然有效。非相关领域不会经常变化,而相关领域往往更具动态性。

4 个答案:

答案 0 :(得分:1)

看看Change Data Capture。这是SQL Server 2008中的一项新功能。

首先在数据库上启用CDC:

EXEC sys.sp_cdc_enable_db

然后,您可以在特定表上启用它,并指定要跟踪的列:

EXEC sys.sp_cdc_enable_table
    @source_schema = 'dbo',
    @source_name = 'xxx',
    @supports_net_changes = 1,
    @role_name = NULL, 
    @captured_column_list = N'xxx1,xxx2,xxx3'

这将创建一个名为cdc.dbo_xxx的更改表。对表中记录所做的任何更改都将记录在该表中。

答案 1 :(得分:1)

我反对!我不能用来描述可用选项的一个词是优雅的。我还没有找到一种令人满意的方式来完成你想要的东西。有选择,但他们都觉得有点不满意。何时/为何选择这些选项取决于您未提及的一些因素。

  • 您多久需要“询问”哪些字段发生了变化?意思是,用户是否不经常点击“审核历史记录”链接?或者这是一直在整理你的应用程序应该如何表现?
  • 磁盘空间需要多少钱?我不是轻率的,但是我已经在我们审计的存储策略是基于我们对圣空间收费的百万美元问题的地方工作 - 这意味着SQL服务器重建不是一个考虑因素,存储大小是。你可能是相同的或相反的。

更改数据捕获

正如@TGnat所说,你可以使用CDC。这种方法很棒,因为您只需启用更改跟踪,然后调用sproc开始跟踪。 CDC很不错,因为它非常有效的存储和马力明智。您也可以设置并忘记它 - 也就是说,直到开发人员出现并想要改变表格的形状。对于开发人员的理智,您需要生成一个禁用/启用实体跟踪的脚本。

我注意到您要排除某些列,而不是包含它们。您可以使用FOR XML PATH技巧完成此操作。您可以编写类似以下内容的查询,然后在调用@capturedColList时使用sys.sp_cdc_enable_table变量。

 SET @capturedColList =   SELECT Substring( (
                SELECT ',' + COLUMN_Name
                FROM INFORMATION_SCHEMA.COLUMNS 
                WHERE TABLE_NAME = '<YOUR_TABLE>' AND
                      COLUMN_NAME NOT IN ('excludedA', 'excludedB')

                FOR XML PATH( '' )  
            )  , 2, 8000)

触发案件 我看到的第二个选项是生成某种代码。它可以是外部线束或SPROC编写您的触发器。无论你的毒药是什么,它都需要自动化和通用化。但是你基本上编写了代码,用于为每个列使用大量unweildy CASE语句将当前与INSERTED或DELETED进行比较的触发器写入。

讨论了风格here

记录所有内容,稍后将其排序

最后一个选项是使用触发器记录每一行的更改。然后,编写代码(SPROCS / UDF),可以查看日志数据并识别发生更改的时间。你为什么选择这个选项?磁盘空间不是问题,虽然你需要能够理解改变了什么,但你很少向系统询问这个问题。

HTH,

-Eric

答案 2 :(得分:0)

使用触发器并确保它可以处理多行插入。

答案 3 :(得分:0)

我在帖子SQL Server Update, Get only modified fields中找到了答案,并根据我的需要调整了SQL(这个sql在触发器中)。 SQL发布如下:

DECLARE @idTable INT SELECT @idTable = T.id FROM sysobjects P JOIN sysobjects T ON P.parent_obj = T.id 在哪里P.id = @@ procid

如果存在  (SELECT * FROM syscolumns WHERE id = @idTable
  AND CONVERT(VARBINARY,REVERSE(COLUMNS_UPDATED()))&amp; POWER(CONVERT(BIGINT,2),colorder-1)&gt; 0并命名NOT IN('timestamp','已审核')         )     开始             - 在这里做适当的事情     END