2010-07-10 35 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,

相關問題