W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
一個觸發(fā)器聲明了當(dāng)執(zhí)行一種特定類型的操作時數(shù)據(jù)庫應(yīng)該自動執(zhí)行一個特殊的函數(shù)。觸發(fā)器可以被附加到表(分區(qū)的或者不分區(qū)的)、視圖和外部表。
在表和外部表上,觸發(fā)器可以被定義為在 INSERT
、UPDATE
或 DELETE
操作之前或之后被執(zhí)行, 可以為每個SQL語句被執(zhí)行一次或者為每個修改的行 被執(zhí)行一次。UPDATE
觸發(fā)器可以進一步地設(shè)置為只針對
UPDATE
語句的SET
子句的特定列出發(fā)。觸發(fā)器也可以被 TRUNCATE
語句觸發(fā)。如果一個觸發(fā)器事件發(fā)生, 觸發(fā)器函數(shù)會在適當(dāng)?shù)氖录徽{(diào)用來處理該事件。
在視圖上,觸發(fā)器可以被定義來取代INSERT
、UPDATE
或 DELETE
操作的執(zhí)行。這種INSTEAD OF
觸發(fā)器對視圖中需要被修改的每一行觸發(fā)一次。觸發(fā)器函數(shù)的職責(zé)是對視圖的底層基本表執(zhí)行必要的修改,并且在合適的時候返回被修改的行以便顯示在視圖中。視圖上的觸發(fā)器也可以被定義為對每個
SQL語句執(zhí)行一次,在INSERT
\UPDATE
或DELETE
操作之前或之后。不過,只有在該視圖上還有一個INSTEAD OF
觸發(fā)器時,上述那些觸發(fā)器才會被觸發(fā)。否則,以該視圖為目標的任何語句都必須被重寫成一個影響其底層基表的語句,然后附著在那些基表上的觸發(fā)器將會被引發(fā)。
觸發(fā)器函數(shù)必須在觸發(fā)器本身被創(chuàng)建之前被定義好。觸發(fā)器函數(shù)必須被定義成一個沒有參數(shù)的函數(shù),并且返回類型為trigger
(觸發(fā)器函數(shù)通過一個特殊傳遞的TriggerData
結(jié)構(gòu)作為其輸入,而不是以普通函數(shù)參數(shù)的形式)。
一旦一個合適的觸發(fā)器函數(shù)被創(chuàng)建,就可以使用CREATE TRIGGER建立觸發(fā)器。同一個觸發(fā)器函數(shù)可以被用于多個觸發(fā)器。
PostgreSQL同時提供每行的觸發(fā)器和每語句的觸發(fā)器。對于一個每行的觸發(fā)器,對于觸發(fā)觸發(fā)器的語句所修改的每一行都會調(diào)用一次觸發(fā)器函數(shù)。相反,一個每語句的觸發(fā)器對于其觸發(fā)語句只被調(diào)用一次,而不管該語句影響了多少行。特別地,一個不影響任何行的語句仍然會導(dǎo)致任何可用每語句的觸發(fā)器的執(zhí)行。這兩類觸發(fā)器有時也分別被稱作行級觸發(fā)器和
語句級觸發(fā)器。TRUNCATE
上的觸發(fā)器只能被定義在語句級。
觸發(fā)器也可以根據(jù)它們是否在操作之前、之后觸發(fā),或者被觸發(fā)來取代操作來分類。它們分別指BEFORE
觸發(fā)器、AFTER
觸發(fā)器以及INSTEAD OF
觸發(fā)器。語句級
BEFORE
觸發(fā)器在語句開始做任何事情之前被觸發(fā),而語句級AFTER
觸發(fā)器則在語句做完所有事情之后被觸發(fā)。這些觸發(fā)器類型可以被定義在表、視圖或外部表上。行級BEFORE
觸發(fā)器在每一個行被操作之前被觸發(fā),而行級AFTER
觸發(fā)器在語句結(jié)束之后被觸發(fā)(但在任何語句級AFTER
觸發(fā)器之前)。這些觸發(fā)器類型只能被定義在表和外部表上,但不能定義在視圖上。
INSTEAD OF
觸發(fā)器只能被定義在視圖上,并且只能定義在行級,當(dāng)視圖中的每一行被標識為需要被操作時,它們會立即觸發(fā)。
一個以繼承或者分區(qū)層次中父表為目標的語句不會導(dǎo)致受影響的子表的語句級觸發(fā)器被引發(fā),只有父表的語句級觸發(fā)器會被引發(fā)。不過,受影響的子表的行級觸發(fā)器將被引發(fā)。
如果一個INSERT
包含ON CONFLICT
DO UPDATE
子句并且引用了EXCLUDED
列,有可能所有行級 BEFORE
INSERT
觸發(fā)器和所有行級 BEFORE
UPDATE
觸發(fā)器的效果可能會以一種對于 被更新行最終狀態(tài)透明的方式被應(yīng)用。不過,對于要執(zhí)行的兩種集合的行級
BEFORE
觸發(fā)器都不需要有EXCLUDED
列引用。當(dāng)同時有行級 BEFORE
INSERT
和 BEFORE
UPDATE
觸發(fā)器影響被插入/ 更新的行時(如果在兩者不冪等時修改或多或少地等價,這仍可能是有問題的),
應(yīng)該考慮可能出現(xiàn)的意料之外的結(jié)果。注意在指定了 ON CONFLICT DO UPDATE
時,不管有沒有行被 UPDATE
影響(并且不管是否采用了其他 UPDATE
路徑),語句級 UPDATE
都將被執(zhí)行。一個帶有 ON CONFLICT DO UPDATE
子句的
INSERT
將首先執(zhí)行語句級BEFORE
INSERT
, 然后執(zhí)行語句級BEFORE
UPDATE
觸發(fā)器, 接著是語句級AFTER
UPDATE
觸發(fā)器,
最后是語句級AFTER
INSERT
觸發(fā)器。
如果一個分區(qū)表上的UPDATE
導(dǎo)致一行移動到另一個分區(qū),它將被從原始分區(qū)DELETE
掉然后再INSERT
到新分區(qū)中。在這種情況下,原始分區(qū)上所有的行級BEFORE
UPDATE
觸發(fā)器和所有行級BEFORE
DELETE
觸發(fā)器會被引發(fā)。然后目標分區(qū)上所有的行級BEFORE
INSERT
觸發(fā)器會被引發(fā)。當(dāng)所有這些觸發(fā)器都影響被移動的行時,應(yīng)該對令人驚訝的結(jié)果有心理準備。至于AFTER ROW
觸發(fā)器,AFTER
DELETE
和
AFTER
INSERT
觸發(fā)器會被應(yīng)用,但AFTER
UPDATE
觸發(fā)器不會被應(yīng)用,因為UPDATE
已經(jīng)被轉(zhuǎn)換成了一個DELETE
和一個INSERT
。對于語句級觸發(fā)器,即便發(fā)生行移動,
DELETE
和INSERT
觸發(fā)器也都不會被引發(fā),只有UPDATE
語句中用到的目標表上的UPDATE
觸發(fā)器將被引發(fā)。
被語句級觸發(fā)器調(diào)用的觸發(fā)器函數(shù)應(yīng)該總是返回NULL
。根據(jù)行級觸發(fā)器的選擇,被其調(diào)用的觸發(fā)器函數(shù)可以返回一個表行(類型HeapTuple
的一個值)給執(zhí)行器。在一個操作前觸發(fā)的行級觸發(fā)器有下列選擇:
它可以返回NULL
來跳過對當(dāng)前行的操作。這指示執(zhí)行器不要執(zhí)行調(diào)用觸發(fā)器的行級操作(對一個特定表行的插入、修改或刪除)。
僅對行級INSERT
和UPDATE
觸發(fā)器來說,被返回的行稱為將要被插入的行或者替代將被更新的行。這允許觸發(fā)器函數(shù)修改將要被插入或更新的行。
一個無意導(dǎo)致任何這些行為的行級BEFORE
觸發(fā)器必須小心地它的結(jié)果,使之和被傳入的行一樣(即,INSERT
和UPDATE
觸發(fā)器的NEW
行,DELETE
觸發(fā)器的OLD
行)。
一個行級INSTEAD OF
觸發(fā)器可以返回NULL
來指示它沒有修改任何來自于視圖底層基表的數(shù)據(jù),也可以返回被傳入的視圖行(INSERT
和UPDATE
操作的NEW
行,或者DELETE
操作的
OLD
行)。一個非空返回值被用于標志觸發(fā)器在視圖中執(zhí)行了必須的數(shù)據(jù)修改。這將會導(dǎo)致被命令修改的行計數(shù)被增加。僅對于INSERT
和UPDATE
操作,觸發(fā)器可能會在返回NEW
行之前對其進行修改。這將會改變INSERT RETURNING
或UPDATE RETURNING
返回的數(shù)據(jù),并在視圖無法正確地顯示提供給它的相同數(shù)據(jù)時有用。
對于在一個操作之后觸發(fā)的行級觸發(fā)器,返回值會被忽略,因此它們可以返回NULL
。
一些情況適用于生成的列。
存儲生成的列在BEFORE
觸發(fā)器之后和 AFTER
觸發(fā)器之前計算. 因此,生成的值可以在AFTER
觸發(fā)器中檢查。 在BEFORE
觸發(fā)器中,OLD
行包含舊的生成的值,正如人們所期待的,但 NEW
行尚未包含新的生成值并且不應(yīng)訪問。
在C語言界面中,此時列的內(nèi)容還沒有被定義;在BEFORE
觸發(fā)器中,高級別編程語言應(yīng)阻止訪問NEW
行中存儲生成的列,。 在BEFORE
觸發(fā)器中更改到生成列的值將被忽略并覆蓋。
如果為同一個關(guān)系上的同一事件定義了超過一個觸發(fā)器,它們將按照其名稱的字母表順序被觸發(fā)。在BEFORE
和INSTEAD OF
觸發(fā)器的情況下,每一個觸發(fā)器返回的可能被修改的行將成為下一個觸發(fā)器的輸入。如果任何一個BEFORE
或INSTEAD OF
觸發(fā)器返回NULL
,該操作將在該行上被禁用并且對于該行不會觸發(fā)后續(xù)的觸發(fā)器。
一個觸發(fā)器定義也能指定一個布爾的WHEN
條件,它將被測試來看該觸發(fā)器是否應(yīng)該被觸發(fā)。在行級觸發(fā)器中,WHEN
條件可以檢查該行的舊列值和/或新列值(語句級觸發(fā)器也能有WHEN
條件,但是該特性對它們不太有用)。在一個BEFORE
觸發(fā)器中,WHEN
條件只是在該函數(shù)被或者將被執(zhí)行前計算,因此使用
WHEN
條件與在該觸發(fā)器函數(shù)的開始測試相同的條件沒有本質(zhì)區(qū)別。不過,在一個AFTER
觸發(fā)器中,WHEN
條件只是在行更新發(fā)生之后被計算,并且它決定在語句的末尾一個事件是否被排隊來觸發(fā)該觸發(fā)器。因此當(dāng)一個AFTER
觸發(fā)器的WHEN
不返回真時,在語句的末尾沒有必要將一個事件進行排隊,也沒有必要重新取出該行。如果觸發(fā)器只對少數(shù)行觸發(fā),這可以使得修改很多行的語句明顯加快。
INSTEAD OF
觸發(fā)器不支持WHEN
條件。
通常,行級BEFORE
被用來檢查或修改即將被插入或更新的數(shù)據(jù)。例如,一個BEFORE
觸發(fā)器可以被用來把當(dāng)前時間插入到一個timestamp
列中,或者檢查該行的兩個元素之間是否一致。行級AFTER
觸發(fā)器大多數(shù)被用來將更新傳播到其他表,或者針對其他表進行一致性檢查。進行這種工作分工的原因是,一個
AFTER
觸發(fā)器可以肯定它看到的是該行的最終值,而一個BEFORE
觸發(fā)器則不能,因為還可能有其他BEFORE
觸發(fā)器在它之后觸發(fā)。如果你不知道讓一個觸發(fā)器是BEFORE
或AFTER
,則BEFORE
形式更加有效,因為關(guān)于該操作的信息直到語句的末尾都不需要被保存。
如果一個觸發(fā)器函數(shù)執(zhí)行 SQL 命令,則這些命令可能會再次引發(fā)觸發(fā)器。這就是所謂的級聯(lián)觸發(fā)器。對于級聯(lián)的層數(shù)沒有直接的限制。級聯(lián)有可能會導(dǎo)致對同一個觸發(fā)器的遞歸調(diào)用。例如,一個INSERT
觸發(fā)器可能執(zhí)行一個向同一個表插入一個額外行的命令,這就導(dǎo)致該INSERT
觸發(fā)器被再次引發(fā)。所以在這種情形下,觸發(fā)器程序員應(yīng)該負責(zé)避免無限遞歸。
在定義一個觸發(fā)器時,可以為它指定參數(shù)。在觸發(fā)器定義中包括參數(shù)的目的是允許具有相似需求的不同觸發(fā)器調(diào)用同一個函數(shù)。例如,可能有一個一般性的觸發(fā)器函數(shù),它需要兩個列名作為參數(shù),一個放當(dāng)前用戶而另一個放當(dāng)前時間戳。在正確編寫的情況下,這個觸發(fā)器函數(shù)應(yīng)該獨立于它所觸發(fā)的表。因此同一個函數(shù)可以被用于具有適當(dāng)列的任意表上的INSERT
事件,這樣做的用途之一是可以自動追蹤一個交易表中記錄的創(chuàng)建。如果被定義成一個UPDATE
觸發(fā)器,它也可以被用來追蹤最新的更新事件。
每一種支持觸發(fā)器的編程語言都有自己的方法來讓觸發(fā)器輸入數(shù)據(jù)對觸發(fā)器函數(shù)可用。這種輸入數(shù)據(jù)包括觸發(fā)器事件的類型(如INSERT
或UPDATE
)以及被列在CREATE TRIGGER
中的任何參數(shù)。對于一個行級觸發(fā)器,輸入數(shù)據(jù)還包括用于INSERT
和UPDATE
觸發(fā)器的
NEW
行,和/或用于UPDATE
和DELETE
觸發(fā)器的OLD
行。語句級觸發(fā)器當(dāng)前沒有任何方法檢查被語句修改的單個行。
默認情況下,語句級觸發(fā)器沒有辦法檢查該語句修改的行。但是AFTER STATEMENT
觸發(fā)器可以請求創(chuàng)建傳遞表,這樣可以讓受影響的行集合對該觸發(fā)器可用。AFTER ROW
觸發(fā)器也可以請求傳遞表,這樣它們可以看到表中的整個變化,同時也能看到當(dāng)前引發(fā)它們的個體行中的變化。檢查傳遞表的方法仍是取決于使用的編程語言,但是通常的方法讓傳遞表變得像觸發(fā)器函數(shù)內(nèi)部發(fā)出的SQL命令能夠訪問的只讀臨時表一樣。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: