2016-02-12 46 views
0

我的問題有點理論性,因爲我沒有任何具體的工作例子。但我認爲值得回答。在SQL Server中編寫插入觸發器的正確​​方法是什麼?

什麼是在SQL Server中編寫插入觸發器的正確​​方法?

比方說,我創建像這樣(或多或少僞代碼)觸發

CREATE TRIGGER MY_TRIGGER 
ON MY_TABLE 
FOR INSERT AS 
    DECLARE @myVariable;    
    DECLARE InsertedRows CURSOR FAST_FORWARD FOR SELECT A_COLUMN FROM INSERTED; 

    OPEN InsertedRows; 
    FETCH NEXT FROM InsertedRows INTO @NewOrderCode; 

    ... 

     INSERT INTO ANOTHER_TABLE (     
      CODE, 
      DATE_INSERTED 
     ) VALUES (      
      @myVariable, 
      GETDATE()  
     ); 

    ...etc 

現在,如果別人創建在同一個表的另一觸發條件和觸發會改變插入的行一些列?這樣

CREATE TRIGGER ANOTHER_TRIGGER 
ON MY_TABLE 
FOR INSERT AS 
    UPDATE MY_TABLE 
    SET A_COLUMN = something 
    WHERE ID IN (SELECT ID FROM INSERTED); 

...etc 

然後我的觸發(如果另一個觸發後被解僱)上的東西不對數據進行操作,因爲插入的數據是不一樣的,其已經改變與其他觸發右表中的實際插入的數據?

總結:

觸發器A於表T更新新插入的行,觸發器B,則對髒數據進行操作,因爲從觸發器A中的更新並不在其中觸發B操作插入的僞代碼表可見。但是如果觸發器B直接在工作臺上工作而不是在僞表INSERTED上,它會通過觸發器A看到更新的數據。

這是真的嗎?我是否應該始終使用表中的數據而不是從INSERTED表中處理數據?

回答

0

觸發器是事務性的。如果您嘗試按照您所描述的方式進行循環更新,則會導致死鎖 - 第一次更新會阻止第二次更新完成。

儘管在查看這段代碼,但您試圖通過INSERTED僞表進行插入來執行插入操作 - 示例中沒有任何內容需要該行爲。如果你直接從完整的INSERTED表中插入,你會得到一個明顯的改進,而且你的第二個觸發器的觸發次數也會減少。

+0

我不明白。誰被誰攔截?兩個觸發器都在插入之後。其中之一是更新兩個觸發器所屬的表,第二個插入另一個表。 – Behnil

+0

是的。但第二次寫入是由第一次寫入觸發的,第一次寫入在執行時尚未完成其事務。它試圖更新的行由原始事務更新,因此被鎖定。試圖在新的環境中更新它們只會給你一個僵局。 – eftpotrm

+0

但我在觸發器中更新。這是否意味着在其表上發生更新時觸發後插入觸發器? – Behnil

4

我通常會建議不要有多個觸發器。如果你願意的話,你可以用define what order來運行。一旦你有更多的東西,你不能控制非第一個非最後一個觸發器的運行順序。

它也越來越難以推斷插入過程中發生了什麼。

相反,我建議每個表單執行一次觸發器,以完成該操作應發生的所有任務。如果您擔心產生的代碼的大小,那通常意味着您應該將代碼一起移出觸發器 - 觸發器應該快速且輕鬆。

相反,您應該開始考慮讓觸發器記錄一個動作,然後使用服務代理或一個SQL Server作業,它可以提取這些記錄並執行額外的處理。重要的是,它在自己的交易中做到這一點,而不是延遲原來的INSERT


我還會告誡您不要在示例1中顯示的當前代碼。考慮編寫一個直接引用insertedINSERT ... SELECT語句,並將所有新行插入到另一個表中,而不是使用遊標和逐行插入行。

+0

謝謝,我感謝你的回答。但我的問題是關於另一個觸發器對其進行操作時由一個觸發器更新的數據的髒狀態。 – Behnil

+1

@Behnil - 我在說,*合併*這些觸發器,以便您不必考慮它們如何獨立運作。 –

3

你應該做的一件事絕對避免在觸發器中使用的是一個CURSOR

一個觸發器應該是非常靈活,小巧,快速 - 和一個遊標是什麼,但!畢竟,它在交易的上下文中被執行,導致它被觸發。不要不必要地延遲完成該交易!

您還需要注意,Inserted包含多個行和編寫相應的觸發,但使用基於集合的技術 - 而不是光標和while循環 - 讓你的觸發迅速,快捷。

不要做繁重,耗時的工作在觸發器 - 剛剛更新了數列,或者使進入另一個表 - 這很好 - NO繁重!,沒有電子郵件發送等!

+0

絕對同意這一點。謝謝。但我的問題是關於另一個觸發器對其進行操作時由一個觸發器更新的數據的髒狀態。 – Behnil

1

我的個人指南SQL觸發幸福

  1. 觸發要輕,速度快。昂貴的觸發器爲EVERYBODY緩慢的數據庫(並不偶然地包括觸發器作者在內的所有人都不滿意)
  2. 請您使用一個觸發操作表組合。 foo表上最多隻有一個插入觸發器。儘管在一張桌子上多次操作的觸發器不一定是壞的。
  3. 不要忘記,inserteddeleted表可能包含多於一行,甚至根本不包含行。無論操作中涉及多少行,快樂的觸發器(更重要的是令人愉快的數據庫用戶和管理員)將表現良好。
  4. 不是不不是曾經在觸發器中使用遊標。服務器端遊標通常是濫用良好實踐,儘管在極少數情況下使用它們是合理的。一個觸發器是從來沒有其中之一。而是將一系列面向集合的DML語句改爲任何類似觸發器的語句。
  5. 請記住有兩類觸發器 - 觸發器AFTER和觸發器INSTEAD OF。在編寫觸發器時考慮這一點。
  6. 永遠不要忽視那些觸發器(AFTERINSTEAD OF)開始執行的時候要比啓動它們的語句運行的上下文大@@trancount
  7. 優先於觸發器的聲明性參照完整性(DRI)作爲保持數據庫中數據一致的手段。某些應用程序完整性規則需要觸發器但是DRI多年來走過了很長的一段路,像row_number()這樣的功能使得觸發器變得不那麼必要。
相關問題