【MySQL 12】觸發器

? ? ?觸發器是一種特殊類型的存儲過程,它不同于之前的我們介紹的存儲過程。觸發器主要是通過事件進行觸發被自動調用執行的。而存儲過程可以通過存儲過程的名稱被調用。?
??????觸發器的主要作用就是能夠實現比參照完整性更為復雜的兩張表或多張表之間的數據的完整性和一致性,從而保證表中的數據的變化符合數據庫設計者確定的業務規則。?
??????觸發器對表進行插入、更新、刪除的時候會自動執行的特殊存儲過程。觸發器一般用在check約束更加復雜的約束上面。?
??????觸發器和普通的存儲過程的區別是:觸發器是當對某一個表進行操作。諸如:update、insert、delete這些操作的時候,系統會自動調用執行該表上對應的觸發器。?
??????sql server 2005中觸發器可以分為兩類:dml觸發器和ddl觸發器,其中ddl觸發器它們會影響多種數據定義語言語句而激發,這些語句有create、alter、drop語句。

DML觸發器分為:

1、 after觸發器(之后觸發)?
??????a、 insert觸發器?
??????b、 update觸發器?
??????c、 delete觸發器?
2、 instead of 觸發器 (之前觸發)?
3、區別?
??????after觸發器:要求只有執行某一操作insert、update、delete之后觸發器才被觸發,且只能定義在表上。?
??????instead of觸發器:表示并不執行其定義的操作(insert、update、delete)而僅是執行觸發器本身。既可以在表上定義instead of觸發器,也可以在視圖上定義。

inserted 表和 deleted 表

? ?在使用觸發器時,SQL Server會為每個觸發器建立兩個特殊的臨時表,即inserted表和deleted表。這兩個表存儲在內存中,與創建觸發器的表具有相同的結構,由系統維護和管理,不允許用戶對其進行修改。每個觸發器只能訪問自己的臨時表,觸發器執行完畢以后,兩表會自動釋放。?
??????(1)inserted表用于存儲insert或update語句所影響的行的副本。當執行insert或update操作時,新的數據行同時被添加到激活觸發器的基本表和inserted表中。?
??????(2)deleted表用于存儲delete或update語句所影響的行的副本。當執行delete或update操作時,指定的原數據行被從基本表中刪除,然后被轉移到deleted表中。一般來說,在基本表和deleted表中不會存在相同的數據行。?
?????? 說明:?
??????update操作分為兩步:首先將基本表中修改的原數據行轉移到deleted表中,然后從inserted表中復制修改后的新數據行到基本表中。也就是說,對于update操作,deleted表中存放的是修改之前的舊值,inserted表中存放的是修改之后的新值。

觸發器創建語法四要素:

1.監視地點(table)?  2.監視事件(insert/update/delete)?  3.觸發時間(after/before)?  4.觸發事件(insert/update/delete)

語法:

delimiter?&&create?trigger?trigger  Nameafter/before?insert/update/delete?on?表名  for?each?row???#這句話在mysql是固定的  beginsql語句;  end&&

商品表

mysql>?create?table?g(  ????->?id?int?auto_increment?primary?key,????->?name?varchar(10),????->?num?int????->?);

訂單表

mysql>?create?table?o(  ????->?idd?int?auto_increment?primary?key,????->?gid?int,????->?much?int????->?);

插入商品:

mysql>?insert?into?g?(name,num)?value?('juzi',20);mysql>?select?*?from?g;  +----+------+------+|?id?|?name?|?num??|  +----+------+------+|??3?|?juzi?|???20?|  +----+------+------+

如果我們在沒使用觸發器之前:假設我們現在賣了3個商品1,我們需要做兩件事

1.往訂單表插入一條記錄

insert?into?o(gid,much)?values(1,3);

2.更新商品表商品1的剩余數量

update?g?set?num=num-3?where?id=1;

創建觸發器:

delimiter?&  mysql>?create?trigger?trg1  ????->?after?insert?on?o????->?for?each?row????->?begin????->?update?g?set?num?=?num?-3?where?id?=?1;????->?end&

執行:

insert?into?o(gid,much)?values(1,3)$

結果:

會發現商品1的數量變為7了,說明在我們插入一條訂單的時候,觸發器自動幫我們做了更新操作。

但現在會有一個問題,因為我們觸發器里面num和id都是寫死的,所以不管我們買哪個商品,最終更新的都是商品1的數量。比如:我們往訂單表再插入一條記錄:insert into o(gid,much) values(2,3),執行完后會發現商品1的數量變4了,而商品2的數量沒變,這樣顯然不是我們想要的結果。我們需要改改我們之前創建的觸發器。

我們如何在觸發器引用行的值,也就是說我們要得到我們新插入的訂單記錄中的gid或much的值。

對于insert而言,新插入的行用new來表示,行中的每一列的值用new.列名來表示。

所以現在我們可以這樣來改我們的觸發器

create?trigger?tg2?  after?insert?on?o?  for?each?row?  begin?  update?g?set?num=num-new.much?where?id=new.gid;(注意此處和第一個觸發器的不同)?  end$

第二個觸發器創建完畢,我們先把第一個觸發器刪掉

drop trigger tg1$

再來測試一下,插入一條訂單記錄:insert into o(gid,much) values(2,3)$

執行完發現商品2的數量變為7了,現在就對了。

現在還存在兩種情況:

1.當用戶撤銷一個訂單的時候,我們這邊直接刪除一個訂單,我們是不是需要把對應的商品數量再加回去呢?

2.當用戶修改一個訂單的數量時,我們觸發器修改怎么寫?

我們先分析一下第一種情況:

監視地點:o表

監視事件:delete

觸發時間:after

觸發事件:update

對于delete而言:原本有一行,后來被刪除,想引用被刪除的這一行,用old來表示,old.列名可以引用被刪除的行的值。

那我們的觸發器就該這樣寫:

create?trigger?tg3  after?delete?on?o  for?each?row  begin  update?g?set?num?=?num?+?old.much?where?id?=?old.gid;(注意這邊的變化)  end$

創建完畢。

再執行

delete?from?o?where?oid?=?2$

會發現商品2的數量又變為10了。

第二種情況:

監視地點:o表

監視事件:update

觸發時間:after

觸發事件:update

對于update而言:被修改的行,修改前的數據,用old來表示,old.列名引用被修改之前行中的值;

修改的后的數據,用new來表示,new.列名引用被修改之后行中的值。

那我們的觸發器就該這樣寫:

create?trigger?tg4  after?update?on?o  for?each?row  begin  update?g?set?num?=?num+old.much-new.much?where?id?=?old/new.gid;  end$

先把舊的數量恢復再減去新的數量就是修改后的數量了。

我們來測試下:先把商品表和訂單表的數據都清掉,易于測試。

假設我們往商品表插入三個商品,數量都是10,

買3個商品1:

insert?into?o(gid,much)?values(1,3)$

這時候商品1的數量變為7;

我們再修改插入的訂單記錄:

update?o?set?much?=?5?where?oid?=?1$

我們變為買5個商品1,這時候再查詢商品表就會發現商品1的數量只剩5了,說明我們的觸發器發揮作用了。

以上就是?【MySQL 12】觸發器的內容,更多相關內容請關注PHP中文網(www.php.cn)!

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享