觸發程序(trigger)是用於在對於Table進行Insert、Update、Delete這三種行為時,會自動"被"執行的程序,所以我們可以在trigger裡寫一堆語法去檢查相關資料、連帶更新其它Table資料......。一般在 SQL SERVER 建立 trigger 時,如無特別定義的話預設是屬於 "After" 的trigger,也就是該Table資料已被異動,當然在trigger中可以對此異動做出復原動作;但如果所定義的是屬於"Before" 的trigger 時,該Table的資料尚未被異動,是否要異動是取決在trigger。
在trigger中SQL SERVER 提供了INSERTED 及 DELETED 這二個特殊暫存資料表格讓我們能更加靈活運用,下表為各異動行為中暫存資料表格裡所儲存的資料別:(若為"After" trigger 時,原資料表格皆未被異動)
異動行為/ 暫存資料表格 | INSERTED | DELETED | 原資料表格 |
INSERT(新增) | 欲新增的"新"資料 | 無資料 | 為新增後的資料 |
DELETE(刪除) | 無資料 | 欲被刪除的資料 | 為刪除後的資料 |
UPDATE(更新) | 影響到資料的更新後資料 | 影響到資料的更新前資料 | 為更新後的資料 |
SQL SERVER 中一個trigger可以指定多重異動行為,所以在trigger中運用特殊暫存資料表格時需多加留意。
我們先建一個測試用資料表格和 Insert 的 Trigger。
程式15~29為建立一個dbo.MMX的After Insert Trigger,檢查欲塞入資料的A欄位值是否已存在dbo.MMX中。
程式32~45為建立一個dbo.MMX的Before Insert Trigger,功能和 dbo.tI_MMX 同樣;44行即當欲新增資料未存在於dbo.MMX時才把資料實際塞入dbo.MMX,如少了這步驟當 Insert Into .....跑完後dbo.MMX 裡並不會多一筆資料出來。
程式47~48:塞入一筆A欄位重覆的資料後發現跑完dbo.tII_MMX即中斷並未繼續執行dbo.tI_MMX,因為我們在42行下了return,所以有資料重覆情況時不會執行到44行程式,所以沒有資料被實際塞到dbo.MMX中,dbo.tI_MMX自然也不會被觸發起來。
程式50~51:塞入一筆未重覆的資料後,dbo.tII_MMX順利將資料INSERT INTO 到 dbo.MMX,連帶會觸發起dbo.tI_MMX的執行。
接下來我們來看看 UPDATE 的 Trigger。
程式53~69:建立一個After的Update Trigger,用來防止A欄位資料重覆。
程式71~95:建立一個Before的Update Trigger,同樣用來防止A欄位資料重覆。
程式75~76:如果一次UPDATE多筆資料時即中斷程式,也不會實際去異動dbo.MMX 裡的資料,為什麼要這麼做,等下會加以說明。
程式89~94:如果A欄位資料未重覆即更新dbo.MMX裡的資料。
為程式97~99執行完後的結果,因A欄位資料重覆所以在dbo.tUI_MMX即攔截掉,所以dbo.tU_MMX尚未被觸發執行。
程式 101~103執行後結果,因A欄位資料未重覆所以在dbo.tUI_MMX中會實際去異動dbo.MMX而觸發dbo.tU_MMX的執行。
Delete Trigger在這邊就省略不再加以說明,其寫法同INSERT、UPDATE Trigger的寫法,不過這邊要加以說明的是Before的INSTEAD OF UPDATE Trigger,相信眼尖的朋友應該已經看到INSTEAD OF UPDATE Trigger的致命點了吧,那即是不管是"Before"或是"After"的Trigger,在SQL SERVER上似乎是"批次"作業,就是如果是一次異動多筆資料其Trigger中的INSERTED及DELETED仍是多筆,而非執行多次的"單筆"Trigger,如果異動欄位又包含Primary Key 欄位時,在INSTEAD OF UPDATE Trigger 中將很難去下UPDATE 語法;在請教google大師後發現此問題好像仍無解,不知這問題有哪位朋友知道解決方式
,另外搜尋到ORACLE的Trigger 有 each row 語法可以下,不知是不是就是執行多次"單筆"Trigger的意思,也請熟悉ORACLE的朋友來賜教。
另外 INSTEAD OF Trigger 也可運用在 VIEW 中......,是的..,我們的確是可以對VIEW進行 INSERT、DELETE、UPDATE 等行為;
程式107~120:建立另一個dbo.MMX2,並將內容資料塞入。
程式122~128:建立一個VIEW,內容為 dbo.MMX 及 dbo.MMX2 JOIN出來的,注意程式126行,此VIEW是使用LEFT OUTER JOIN(外部聯結) 方式 JOIN出來的唷,所以dbo.MMX.A = 'C' 並無此筆資料,但透過外部聯結仍可呈現完整資料。
程式132~134:對dbo.VIEW_MMX 進行UPDATE行為時出現了4406的錯誤,不知是否因為用外部聯結而造成的???
程式136~164:建立INSTEAD OF UPDATE Trigger;
程式139為判斷可異動到Car_ID或Car_Name二欄位時即中斷程式;
程式141~162:建立一個Cursor 來逐筆對dbo.MMX進行實際異動;
程式149~156:因此VIEW是以外部聯結JOIN出來的,所以Car_Qty=0的資料有可能根本不存在於dbo.MMX中,所以我們需要一個判斷來決定我們對dbo.MMX是要進行INSERT或是UPDATE異動行為。
程式166~167:先將UPDATE前資料顯示出來。
程式169~170:針對VIEW下UPDATE語法(多筆批次更新)。
程式172~173:UPDATE後的資料。
異動前資料,dbo.MMX.A = 'C' 目前無此筆資料存在。
異動後資料,dbo.tUI_VIEW_MMX 為我們將 A in ('A','B','C') 等三筆資料的B欄位各加上2且INSERT一筆A='C'資料進來了 。
VIEW 的確是可被UPDATE,至於INSERT及DELETE相信也是可以辦得到的,如此看來INSTEAD OF Trigger 似乎較適合用在VIEW 的異動。
說到VIEW的異動,記得在軟體公司任職時,公司有請微軟講師來講解.NET開發工具,其中有提到VIEW可以做自動分割儲存,就是如果一個VIEW是來自數個不同Table,而這些Table有共同欄位,當異動資料時,SQL SERVER會依"設定"去異動實際Table,不過這功能名稱我忘了,改天再來測式一下囉。
SQL Script File:
http://cid-a640a79fdbb7450d.skydrive.live.com/embedrowdetail.aspx/BOLG%20Temp%20Files/Trigger%e6%b8%ac%e8%a9%a6Script.sql
1 則留言:
你在給我投綠的
就欠扁啦
為了我的股票
2號啦
張貼留言