在我们的业务规则中,我们需要跟踪何时指定一行被更改。该表包含根据我们的业务目的指定为不相关的多个列(例如输入日期字段,时间戳,查看位字段或接收位字段)。该表有很多列,我试图找到一种优雅的方法来确定是否有任何相关字段已更改,然后在审计表中记录一个条目(输入行的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])
我正在尝试找到一种通用方法,我可以指定忽略字段,即使我在表中添加了其他相关字段,存储过程仍然有效。非相关领域不会经常变化,而相关领域往往更具动态性。
答案 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)
我反对!我不能用来描述可用选项的一个词是优雅的。我还没有找到一种令人满意的方式来完成你想要的东西。有选择,但他们都觉得有点不满意。何时/为何选择这些选项取决于您未提及的一些因素。
更改数据捕获
正如@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