我在SQLCLR程序集中实现了后触发器.在其中我想知道,哪些列已经真正更新(并且它们的值已被更改).
不幸的是,即使列值仍然相同,SqlContext.TriggerContext.IsUpdatedColumn也会返回true.我想,这只是因为由非智能服务器应用程序准备的SQL查询会重写所有列,即使其中一些列尚未被用户更改.
第二个问题是某些列具有ntext类型,因此我甚至无法从INSERTED伪表中选择它们(MS SQL Server不允许SELECT字段具有来自INSERTED的ntext类型).这就是为什么现在我使用以下查询SELECT更改行:
SELECT * FROM [dbo].[MyTable] WHERE [id] IN (SELECT [id] FROM INSERTED)
我该怎么做才能知道哪些列不仅更新了,而是更改了?
现在我有一个简单的想法:创建另一个触发器,BEFORE,并从内部保存更新的行.然后,当执行AFTER触发时,比较列值.这个想法是我能做的最好的事情吗?如果是这样,在BEFORE和AFTER触发器之间保留更改行的最佳位置是什么?在执行AFTER触发器之前,将删除临时表,因为我关闭了上下文连接(可能只是不关闭?).
最佳答案 好的,现在我已经解决了这个问题.
首先,我创建了源表的完整副本(数据结构):
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 voila – 您只选择了真正改变的行.
最后,在触发器结束时,不要忘记使用新值更新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
也许,有一个更好的解决方案,但这也有效.
问候,