2010-07-10 83 views
4

我在SQLCLR程序集中实现了一个后触发器。在其中我想知道,哪些列已经真正更新(并且其值已更改)。我想知道,哪些列已被真正改变

不幸的是,SqlContext.TriggerContext.IsUpdatedColumn返回true,即使列值仍然相同。我想,这只是因为由一个不太聪明的服务器应用程序准备的SQL查询会重写所有列,即使其中一些列尚未被用户更改。

第二个问题是某些列有ntext类型,所以我甚至无法从INSERTED伪表中选择它们(MS SQL Server不允许SELECT字段具有来自INSERTED的ntext类型)。这就是为什么我现在选择在变行用下面的查询:

SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED) 

我应该怎么做去了解,不只是更新哪些列,但改变了吗?

现在我有一个简单的想法:创建另一个触发器,BEFORE,并从内部保存更新的行。然后,当AFTER触发器正在执行时,比较列值。这个想法是我能做的最好的事情吗?如果是这样,在BEFORE和AFTER触发器之间保持更改行的最佳位置是什么?在执行AFTER触发器之前,临时表将被删除,因为我关闭了上下文连接(可能只是不关闭?)。

回答

2

好的,现在我已经解决了这个问题。

首先,我创建源表(数据+结构)的完整副本:

IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'copyTable') 
SELECT * INTO copyTable FROM MyTable 

然后,我用它在我的触发年初副本比较源表:

SELECT A.* FROM MyTable A, copyTable B WHERE 
    A.id IN (SELECT [id] FROM INSERTED) AND 
    A.id = B.id AND 
    A.{0} <> B.{0} 

将{0}替换为您所需的列。这一栏就是你必须知道的栏目,是否更新。就我而言,它是动态定义的,但您可以静态计算您需要的所有列。

Et瞧 - 你只是选择了真正改变的行。

最后,在触发结束,不要忘记用新的值更新copyTable:

UPDATE copyTable SET 
    id = s.id, 
    col1 = s.col1, 
    ... all columns you'd like to control ... 
FROM MyTable s WHERE 
    s.id IN (SELECT [id] FROM INSERTED) AND 
    copyTable.id = s.id 

也许,有一个更好的解决方案,但这个工作太为好。

Regards,

相关问题