2011-08-09 108 views
1

我試圖在觸發器中使用T-sql中的更新函數來檢查列是否已更改。這是我在做什麼:TSQL:使用觸發器中的更新的非布爾類型指定錯誤

declare column_name cursor for select name from sys.columns where object_id = object_id(N'tblKit') 
open column_name 

fetch column_name into @colname 
while (@@Fetch_status=0) 
begin 
if(Update(@colname)) 

我得到一個錯誤說非布爾類型指定的條件是預期的。這是msdn論壇中使用的語法。那麼這有什麼問題嗎?

我使用Microsoft SQL Server 2008 Management Studio中

+1

是不是應該結束前的腳本?我缺少一個「END」和「IF」語句 –

+0

我不相信你可以調用Update(後一個命令)一樣,(通過在PARAM)或許COLUMNS_UPDATED()(http://msdn.microsoft。 com/en-us/library/ms186329(v = SQL.90).aspx)位掩碼可能更適合您的需要。 很可能有一個更好的方式做你想要完全做什麼。如果你發佈整個觸發器 –

+0

,這將是有益的,這是我想要做的。當表更新時,我試圖將更新列的舊值和新值單獨存儲在表中。對於更新函數,我遵循http://msdn.microsoft.com/en-us/library/ms187326(v=SQL.100).aspx中的語法。但是我不知道我是否可以在函數中使用靜態變量。我可以直接使用列名。使用爲我的情況更新的列的問題是我必須檢查近25列,所以必須爲它們創建一個位掩碼。我也認爲可能有更好的方法來做到這一點。但還不知道。 ty – deepak

回答

2

如果你只是想記錄各列的變化在你的扳機,你可以嘗試unpivoting,可能與全加入一起。我們的想法是,你既UNPIVOT和inserted然後deleted加入他們放在桌上的鑰匙和含逆轉置名稱列,篩選出其中的值相同的行。

下面是該方法的示例說明。

首先,該表的定義:

CREATE TABLE TestTable (
    ID int IDENTITY PRIMARY KEY, 
    Attr1 int, 
    Attr2 int, 
    Attr3 int 
); 

CREATE TABLE TestTableLog (
    ID int IDENTITY PRIMARY KEY, 
    TableID int, 
    AttrName sysname, 
    OldValue int, 
    NewValue int, 
    Timestamp datetime DEFAULT GETDATE() 
); 

接下來,記錄變化的觸發。這一次會抓住所有的操作:插入,更新和刪除:

CREATE TRIGGER trTestTable ON TestTable 
AFTER INSERT, UPDATE, DELETE 
AS BEGIN 
    WITH inserted_unpivot AS (
    SELECT 
     ID, 
     AttrName, 
     Value 
    FROM inserted i 
    UNPIVOT (Value FOR AttrName IN (Attr1, Attr2, Attr3)) u 
), 
    deleted_unpivot AS (
    SELECT 
     ID, 
     AttrName, 
     Value 
    FROM deleted d 
    UNPIVOT (Value FOR AttrName IN (Attr1, Attr2, Attr3)) u 
) 
    INSERT INTO TestTableLog (TableID, AttrName, OldValue, NewValue) 
    SELECT 
    ISNULL(i.ID, d.ID), 
    ISNULL(i.AttrName, d.AttrName), 
    d.Value, 
    i.Value 
    FROM inserted_unpivot i 
    FULL JOIN deleted_unpivot d 
     ON i.ID = d.ID AND i.AttrName = d.AttrName 
    WHERE CASE i.Value WHEN d.Value THEN 0 ELSE 1 END = 1 
END 

現在,讓我們充滿TestTable的一些數據:

WHILE (SELECT COUNT(*) FROM TestTable) < 15 
    INSERT INTO TestTable 
    SELECT RAND() * 1000, RAND() * 1000, RAND() * 1000 
; 

這裏的後續變化之前,它的內容:

ID   Attr1  Attr2  Attr3 
----------- ----------- ----------- ----------- 
1   820   338   831 
2   795   881   453 
3   228   430   719 
4   36   236   105 
5   246   115   649 
6   488   657   438 
7   990   360   15 
8   668   978   724 
9   872   385   562 
10   460   396   462 
11   62   599   630 
12   145   815   439 
13   595   7   54 
14   587   85   655 
15   80   606   407 

現在讓我們對內容進行一些修改:

UPDATE TestTable SET Attr2 = 35 WHERE ID = 3; 
UPDATE TestTable SET Attr3 = 0 WHERE ID BETWEEN 6 AND 10; 
INSERT INTO TestTable VALUES (1, 1, 1); 
DELETE FROM TestTable WHERE ID = 14; 

下面是我們在TestTable事後得:

ID   Attr1  Attr2  Attr3 
----------- ----------- ----------- ----------- 
1   820   338   831 
2   795   881   453 
3   228   35   719 
4   36   236   105 
5   246   115   649 
6   488   657   0 
7   990   360   0 
8   668   978   0 
9   872   385   0 
10   460   396   0 
11   62   599   630 
12   145   815   439 
13   595   7   54 
15   80   606   407 
16   1   1   1 

而這正是已被記錄:

ID   TableID  AttrName OldValue NewValue Timestamp 
----------- ----------- ----------- ----------- ----------- ----------------------- 
1   3   Attr2  430   35   2011-08-22 20:12:19.217 
2   10   Attr3  462   0   2011-08-22 20:12:19.227 
3   9   Attr3  562   0   2011-08-22 20:12:19.227 
4   8   Attr3  724   0   2011-08-22 20:12:19.227 
5   7   Attr3  15   0   2011-08-22 20:12:19.227 
6   6   Attr3  438   0   2011-08-22 20:12:19.227 
7   16   Attr1  NULL  1   2011-08-22 20:12:19.227 
8   16   Attr3  NULL  1   2011-08-22 20:12:19.227 
9   16   Attr2  NULL  1   2011-08-22 20:12:19.227 
10   14   Attr1  587   NULL  2011-08-22 20:12:19.230 
11   14   Attr2  85   NULL  2011-08-22 20:12:19.230 
12   14   Attr3  655   NULL  2011-08-22 20:12:19.230 

的設置,當然,已經有所簡化。特別是,所有要記錄的主表的列都是相同的類型,因此不需要將數據轉換爲某種泛型來包含各種數據。但也許這就是你需要的。如果不是,我相信這可以爲實施最終解決方案提供良好的開端。

+0

這非常緊密。 – JustinStolle

+0

難道是值得的存儲新舊值與XML及其數據類型一起?這樣你就不會陷入只有一種數據類型有用的新舊列(在你的例子中爲'int's)。 – JustinStolle

+0

@JustinStolle:很好的問題,但說實話,我目前對XML的經驗很少,所以不能真正說。 –