簡介
觸發程式(trigger) 是一種特殊的預存程式,執行特定的陳述式(UPDATE、INSERT 或 DELETE)就可以啟動觸發程式。觸發程式與其他預存程式相同,可以是由簡單,亦或是複雜的 T-SQL 陳述式組成;至於與其他預存程式不同的地方,則在於當指定的資料被修改,觸發程式即自動執行,無法依名稱以手動執行。觸發程式執行時,稱為觸動(fire)。觸發程式雖建立在現有的資料庫資料表中,但它可以存取其他資料庫的資料表和物件。觸發程式不能建立在臨時的資料表或臨時的系統資料表上,只能建立在使用者自訂資料表或自訂的檢視表中。執行觸發程式所在的資料表或檢視表,稱為觸發程式資料表(trigger table)。
類型
觸發程式有五種類型:UPDATE、INSERT、DELETE、INSTEAD OF 和 AFTER。有了觸發程式,只要您對該表格更新、插入或刪除時,就會觸動對應的 UPDATE、INSERT 或 DELETE 觸發程式。INSTEAD OF 和 AFTER 是 SQL 2000 新增的兩項觸發程式,Instead of的原義是「取代」,INSTEAD OF觸發程式會取代插入、更新和刪除操作而執行。AFTER 觸發程式會在觸發動作之後再觸動,可視為控制觸發程式啟動時間的機制。
對資料的更新、插入及刪除被視為資料修改事件。您可以設計當一項或多項修改事件產生時,即觸動觸發程式。例如,當執行 UPDATE 或 INSERT 陳述式時即觸動觸發程式。這種類型的觸發程式稱為 UPDATE/INSERT 觸發程式。您也可以建立任何一項修改事件產生時,執行相對的 UPDATE/INSERT/DELETE 觸發程式。
規定
下面是關於觸發程式的一些其他規定:
觸發程式只在觸發它的陳述式完成後執行。舉例來說,如果 UPDATE 陳述式成功,UPDATE 觸發程式才會被觸動。
如果陳述式在資料表中執行違反條件約束或引起錯誤,觸發程式不會觸動。
觸發程式視為單一交易中的一部份,因此可以由原觸發程式復原交易,如果在交易過程中偵測到嚴重的錯誤(如使用者中斷連線),則會自動復原整個交易。
一個陳述式只能觸動一次觸發程式。
當觸發程式觸動,若產生任何結果,就會如預存程式一樣,將結果傳回其呼叫的套用程式。一般來說,INSERT、UPDATE 或 DELETE 的陳述式(觸動觸發程式的陳述式)不會將結果傳回;結果通常由 SELECT 查詢傳回。因此,為了避免觸發程式傳回結果給套用程式,請勿在觸發程式定義中引入 SELECT 陳述式或指派變數。如果希望從觸發程式中傳回結果,在允許修改觸發資料表的每個套用程式中都必須撰寫特殊的程式,才能使套用程式收到傳回的資料並進行正確的處理。
如果您必須在觸發程式中指派變數,則可在觸發程式的起始位置使用 SET NOCOUNT ON 陳述式以防止傳回任何結果資料列。SET NOCOUNT 陳述式指定是否傳回查詢或受陳述式影響的資料列數目的資訊(例如,影響 23 個資料列)。SET NOCOUNT 的預設值是設在 OFF,也就是說會傳回受影響列的訊息。該設定並不影響 SELECT 陳述式實際結果的傳回,只傳回計數。
一、認識觸發程式
使用觸發程式程式的好處是SQL Server會使用觸發程式以自動執行該觸發程式所定義的命令,這使得資料庫功能性更為強大。因此只要您事先定義觸發程式,您不需要擔心資料庫客戶端(這包含了使用者或應用程式)是否了解所有的資料依存性和商業規則。
舉例來說,一位業務員已經規劃了一個訂單總計等於或大於$10,000時,就必須要進行信用檢查的規則。假如CreditApproved是指Customer資料表內的一個資料行,而現在有一筆訂單的相關資料要新增至Order資料表中,此時您無法使用CHECK條件約束來執行此規則。但是更令人煩惱的是您要在資料庫客戶端強制這些規則更為困難,於是觸發程式就可以提供在資料庫本身進行建置此規則的機制。
觸發程式也可以用於避免客戶端變更資料庫規則。繼續前一個範例,假如將商業規則更改為金額大於或等於$15,000時才需要信用驗證時,這個新的規則可以在資料庫層級建置,而您不需要檢查和更新所有客戶端的應用程式。
觸發程式最典型的使用方式是-商業規則無法使用資料表條件約束強制建置時,就使用觸發程式。觸發程式很早就已經需要串聯參考完整性(cascading referential integrity)的功能,但是直到SQL Server 2000這個版本才支持。然而,現在我們可以在資料表層級使用觸發程式建置串聯參考完整性,就像剛才的範例一樣。大多數的商業規則會涉及多個資料表-例如計算總和需要使用到其它的資料表,這通常藉由觸發程式會比較容易建置。
提示縱使觸發程式的執行效能並不是問題的重點所在(當它和資料指針一起使用時),您應該儘可能的使用較低階的方式建置規則。假如您的商業規則可以利用CHECK條件約束建置時,您就不應該使用觸發程式;而如果您可以使用UNIQUE條件約束時,您就不應該使用CHECK條件約束。
AFTER觸發程式
SQL Server 2000支持了二種不同的觸發程式型態:AFTER觸發程式和INSTEAD OF觸發程式。觸發的情況分別如下:AFTER觸發程式將會在其所定義的命令執行後被觸發;INSTEAD OF觸發程式將會代替其所定義的命令被觸發。
您可以針對INSERT、UPDATE和DELETE命令建立AFTER觸發程式。AFTER觸發程式只能在資料表上建立,而不能在檢視表上建立。但是您可以針對這三個命令分別建立多個觸發程式,相對地,單一的觸發程式也可以套用這三個命令的任意組合。
提示
假如您針對單一個命令建立多個觸發程式時,您可以使用系統預存程式sp_settriggerorder來設定該命令執行時的第一個和最後一個觸發程式。
AFTER觸發程式會在所有的條件約束被處理之後再觸發,假如有違反條件約束的情況發生時,該AFTER觸發程式將不會被觸發。
舉例來說,假如在資料表中試圖新增資料列而導致違反PRIMARY KEY條件約束時,該INSERT陳述式會在呼叫觸發程式之前就發生執行失敗。
INSTEAD OF觸發程式
INSTEAD OF觸發程式會取代其所定義的命令被觸發。就像AFTER觸發程式一樣,您可以在INSERT、UPDATE或DELETE命令中定義INSTEAD OF觸發程式。單一的觸發程式可以套用多重命令的任意組合。
與AFTER觸發程式不同的是,您可以針對資料表和檢視表來建立INSTEAD OF觸發程式,但是在資料表或檢視表上的每一個動作,您只能建立單一個INSTEAD OF觸發程式。
INSTEAD OF觸發程式不兼容於串聯參考完整性。INSTEAD OF DELETE與INSTEAD OF UPDATE觸發程式不能定義於以DELETE或UPDATE動作定義外部索引鍵的資料表。
因為INSTEAD OF觸發程式可以宣告在檢視表中,所以它們非常地適用於建置檢視表的功能性。舉例來說,針對一個包含有GROUP BY子句的檢視表來說,SQL Server會防止使用INSERT陳述式,但是卻允許您針對該檢視表定義一個INSTEAD OF INSERT觸發程式。您可以使用該觸發程式以將資料列插入定義檢視表的底層資料表中。
BEFORE觸發程式
就本質上而言,是沒有BEFORE觸發程式的。但是INSTEAD OF觸發程式可以代替其所定義的命令執行。如果沒有INSTEAD OF觸發程式存在,則該命令就會真的執行。
舉例來說,假如您想要在INSERT之前檢查某些條件時,您可以宣告一個INSTEAD OF INSERT觸發程式。該INSTEAD OF觸發程式將執行此檢查,然後在資料表中執行INSERT。該INSERT陳述式將會正常地執行,而不需要遞歸地呼叫INSTEAD OF觸發程式。
二、建立觸發程式
SQL Server使用觸發程式來處理一些條件約束。您無法使用觸發程式CREATE、ALTER或DROP資料庫、您無法使用觸發程式將資料庫或交易記錄檔案進行還原、並且您無法使用觸發程式進行更改SQL Server設定的操作(您可以參考「SQL Server線上叢書」所提供的完整說明)。
假如您在觸發程式中更改資料庫選項時,您所更改的選項只會在觸發程式執行期間有效,但是在觸發程式執行完畢之後,您所更改的值將會恢復到原來的值。
理論上,您可以使用RETURN陳述式自觸發程式中傳回一個值,但是您不應該依賴客戶端應用程式來探知該觸發程式是否存在或該觸發程式作了什麼。raiserror命令提供了一個比較好的技術,因為大多數的應用程式的設計會掌控這些錯誤。
使用CREATE TRIGGER命令
就像其它的資料庫對象一樣,您可以使用CREATE陳述式的形式建立一個觸發程式。CREATE陳述式的基本語法為:
CREATE TRIGGER trigger_name ON table_or_view trigger_type command_list AS SQL_statements其中trigger_name必須要遵守唯一性的規則,假如trigger_type是INSTEAD OF時,table_or_view可以是檢視表名稱,因為您只可以在檢視表中定義INSTEAD OF觸發程式。觸發程式不能建立在暫存資料表或系統資料表中,但是它們可以引用暫存資料表。
trigger_type關鍵字只能是AFTER、FOR或INSTEAD OF其中之一;command_list可以聯合使用任何INSERT、UPDATE或DELETE命令,假如您要使用一個以上的命令時,您可以使用逗號「,」將這些命令區隔開來。
提示
早期的SQL Server版本僅支持AFTER觸發程式和trigger_type FOR語法,此語法在SQL Server 2000中也有支持,但是它與AFTER所表示的意思是相同的。
三、儲存觸發程式
您可將觸發程式儲存至資料庫中。在儲存全新或更新的觸發程式時,觸發程式會加入資料表 資料夾中。
若要儲存觸發程式
在檔案選單中,按一下儲存 《觸發程式名稱》。
如果更新現存觸發程式,則會出現訊息框,提示您確認是否要進行儲存動作。請選擇是。
顯示於伺服器總管內 資料表資料夾中的已儲存觸發程式,位於其所屬的資料表下。
四、開啟觸發程式
您可開啟觸發程式,來檢視或編輯資料庫中現存觸發程式的文字。觸發程式在 Transact-SQL for Microsoft® SQL Server™ 資料庫或 PL/SQL for Oracle 資料庫中編寫指令碼。
在伺服器總管中,觸發程式與資料庫資料表資料行是以觸發程式圖示來區分。
若要開啟觸發程式
在伺服器總管內,展開資料表資料夾。
將準備開啟的觸發程式所在的資料表展開。
在準備開啟的觸發程式名稱上按一下滑鼠右鍵,並於快速鍵選單上選擇 編輯觸發程式。或連按兩下您要開啟的觸發程式名稱。
觸發程式在可用以編輯 SQL 陳述式的原始程式代碼編輯器中開啟。
五、刪除觸發程式
您可刪除資料庫中不再需要,或者會執行不必要動作的觸發程式。例如,如果您使用資料庫圖表來設計資料庫,則會使用關聯性來實行參考完整性,而非使用觸發程式。如果觸發程式重複了資料庫圖表內的關聯性,則應該刪除觸發程式或者關聯性。如需刪除關聯性的詳細信息,請參閱刪除關聯性。
若要刪除觸發程式
在伺服器總管內,展開資料表資料夾。
將準備刪除的觸發程式所在的資料表展開。
在準備刪除的觸發程式上,按一下滑鼠右鍵,並於快速鍵選單上選擇 刪除。
會出現訊息提示您確認是否刪除。請選擇是。
觸發程式自資料庫與伺服器總管中刪除。
六、使用觸發程式的優點
觸發程式適用於下列方式:
觸發程式是自動的。觸發程式在資料表內的資料經過修改 (例如手動輸入或應用程式動作) 後,會立即激活。
觸發程式可透過資料庫的關聯資料表串聯 (Cascade) 變更。例如,您可以在 titles 資料表的 title_id 資料行中,寫入某個刪除觸發程式,以便刪除其它資料表中相符的資料列。觸發程式使用 title_id 資料行做為唯一鍵,以便從 titleauthor、sales 和 roysched 資料表中找出符合的資料列。
注意在 SQL Server 2000 環境下,也可以透過關聯資料表串聯變更;方法是在外部索引鍵條件約束中設定 CASCADE UPDATE 或 DELETE (或同時設定兩種) 條件約束。
觸發程式可實行檢查條件約束中所定義更為複雜的限制。觸發程式與檢查條件約束不同,前者可以參考其它資料表內的資料行。例如,觸發程式可以將嘗試套用折扣的更新項目 (儲存於 discounts 資料表) 復原為書籍 (儲存於 titles 資料表),其價格會低於 $10。
如需使用條件約束的詳細信息,請參閱下列主題:
至 | 請參閱 |
建立新觸發程式 | 建立觸發程式 |
開啟現存觸發程式 | 開啟觸發程式 |
將觸發程式儲存至您的項目中 | 儲存觸發程式 |
使用 INSTEAD OF 觸發程式 | 在檢視中使用 INSTEAD OF 觸發程式 |
刪除預存觸發程式 | 刪除觸發程式 |
如需詳細信息以及觸發程式的範例,請參閱您的資料庫伺服器檔案。如果您使用 Microsoft SQL Server,請參?。
七、何時使用觸發程式
觸發程式和條件約束相同,可用來維持資料的完整性和商業規則,但是觸發程式不能取代條件約束。例如,您不需要建立觸發程式來檢查資料表中主索引鍵中的某個值是否存在,才能決定這個值是否能被插入到另一個資料表中的相對應資料行(外部索引鍵條件約束在這種情況下才是一個較好的選擇)。您應當建立一個觸發程式來啟動資料庫中所有相關資料表的串聯變更,例如,您可能在 pubs 資料庫中titles這個資料表中的title_id資料行上建立 DELETE 觸發程式,當您在titles欄位中刪除一筆資料時,在sales、roysched和titleauthor資料表中對應資料的資料行也會被刪除(在接下來的章節我們將看到如何建立該 DELETE 觸發程式)。
您還可以利用觸發程式執行比 CHECK 條件約束更複雜的資料檢測(CHECK 條件約束在 第十六章 有詳細討論)。由於觸發程式可以引用其他資料表中的資料行,因此才可能執行複雜的資料檢測;反之,CHECK 條件約束只限於在其所定義的資料表上執行。
您還可以建立多重觸發程式,當資料修改時即觸動所有觸發程式。(請記住,如果在資料表或檢視表中為一個事件定義多重觸發程式,每個觸發程式都必須有一個自己的名稱)。
或者您可以建立單一觸發程式,在資料修改時即被觸動。也就是每一次當被定義的事件發生,觸發程式就被觸動一次。因此,若是在資料表上定義 INSERT、UPDATE 和 DELETE 的觸發程式,每次定義的事件產生時,觸發程式就會觸動。
在建立觸發程式時,SQL Server 會為觸發程式建立兩個暫時資料表,您可以參考這兩個資料表,用 T-SQL 撰寫觸發程式定義。這些資料表固定儲存在與觸發程式一起的記憶體中,每個觸發程式只能存取自己的暫時資料表,暫時資料表即為觸發程式所在資料表的一個副本。您可以使用這些資料表比較資料修改前後狀態。下一節將列舉這些特殊資料表(稱為deleted和inserted資料表)。
MYSQL如何創建觸發程式
語法:CREATE TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW trigger_stmt
文字說明第一次看的時候不是很明白,但是最後面的看一下例子就差不多了!
觸發程式是與表有關的命名資料庫對象,當表上出現特定事件時,將激活該對象。
觸發程式與命名為tbl_name的表相關。tbl_name必須引用永久性表。不能將觸發程式與TEMPORARY表或視圖關聯起來。
trigger_time是觸發程式的動作時間。它可以是BEFORE或AFTER,以指明觸發程式是在激活它的語句之前或之後觸發。
trigger_event指明了激活觸發程式的語句的類型。trigger_event可以是下述值之一:
INSERT:將新行插入表時激活觸發程式,例如,通過INSERT、LOAD DATA和REPLACE語句。
UPDATE:更改某一行時激活觸發程式,例如,通過UPDATE語句。
DELETE:從表中刪除某一行時激活觸發程式,例如,通過DELETE和REPLACE語句。
請注意,trigger_event與以表操作方式激活觸發程式的SQL語句並不很類似,這點很重要。例如,關於INSERT的BEFORE觸發程式不僅能被INSERT語句激活,也能被LOAD DATA語句激活。
可能會造成混淆的例子之一是INSERT INTO .. ON DUPLICATE UPDATE ...語法:BEFORE INSERT觸發程式對於每一行將激活,後跟AFTER INSERT觸發程式,或BEFORE UPDATE和AFTER UPDATE觸發程式,具體情況取決於行上是否有重複鍵。
對於具有相同觸發程式動作時間和事件的給定表,不能有兩個觸發程式。例如,對於某一表,不能有兩個BEFORE UPDATE觸發程式。但可以有1個BEFORE UPDATE觸發程式和1個BEFORE INSERT觸發程式,或1個BEFORE UPDATE觸發程式和1個AFTER UPDATE觸發程式。
trigger_stmt是當觸發程式激活時執行的語句。如果你打算執行多個語句,可使用BEGIN ... END複合語句結構。這樣,就能使用存儲子程式中允許的相同語句。
使用別名OLD和NEW,能夠引用與觸發程式相關的表中的列。OLD.col_name在更新或刪除它之前,引用已有行中的1列。NEW.col_name在更新它之後引用將要插入的新行的1列或已有行的1列。
激活觸發程式時,對於觸發程式引用的所有OLD和NEW列,需要具有SELECT許可權,對於作為SET賦值目標的所有NEW列,需要具有UPDATE許可權。
注釋:目前,觸發程式不會被級聯的 外鍵動作激活。該限制將會被儘早放寬。
CREATE TRIGGER語句需要SUPER許可權。
示例:
CREATE TRIGGER update_blogs AFTER INSERT ON blogs FOR EACH ROW
UPDATE blogcategory SET amount = amount + 1 WHERE cid = NEW.categoryid;
該語句創建了一個名為update_blogs的觸發程式,這個觸發程式在blogs表發生INSERT、LOAD DATA和REPLACE語句時執行“UPDATE blogcategory SET amount = amount + 1 WHERE cid = NEW.categoryid;”