MySql觸發器學習

Why Triggers 爲什麼要用觸發器
  我們在MySQL 5.0中包含對觸發器的支持是由於以下原因:
  MySQL早期版本的用戶長期有需要觸發器的要求。
  我們曾經許諾支持所有ANSI標準的特性。
  您可以使用它來檢查或預防壞的數據進入數據庫。
  您可以改變或者取消INSERT, UPDATE以及DELETE語句。
  您可以在一個會話中監視數據改變的動作。
  在這裏我假定大家都讀過"MySQL新特性"叢書的第一集--"MySQL存儲過程",那麼大家都應該知道MySQL至此存儲過程和函數,那是很重要的知識,因爲在觸發器中你可以使用在函數中使用的語句。特別舉個例子:
  複合語句(BEGIN / END)是合法的.
  流控制(Flow-of-control)語句(IF, CASE, WHILE, LOOP, WHILE, REPEAT, LEAVE,ITERATE)也是合法的.
  變量聲明(DECLARE)以及指派(SET)是合法的.
  允許條件聲明.
  異常處理聲明也是允許的.
  但是在這裏要記住函數有受限條件:不能在函數中訪問表.因此在函數中使用以下語句是非法的。

ALTER 'CACHE INDEX' CALL COMMIT CREATE DELETE
DROP 'FLUSH PRIVILEGES' GRANT INSERT KILL
LOCK OPTIMIZE REPAIR REPLACE REVOKE
ROLLBACK SAVEPOINT 'SELECT FROM table'
'SET system variable' 'SET TRANSACTION'
SHOW 'START TRANSACTION' TRUNCATE UPDATE

  在觸發器中也有完全一樣的限制.

  觸發器相對而言比較新,因此會有(bugs)缺陷.所以我在這裏給大家警告,就像我在存儲過程書中所說那樣.不要在含有重要數據的數據庫中使用這個觸發器,如果需要的話在一些以測試爲目的的數據庫上使用,同時在你對錶創建觸發器時確認這些數據庫是默認的。

Syntax 語法
  1. Syntax: Name 語法:命名規則

CREATE TRIGGER <觸發器名稱> <--
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON <表名稱>
FOR EACH ROW
<觸發器SQL語句>

  觸發器必須有名字,最多64個字符,可能後面會附有分隔符.它和MySQL中其他對象的命名方式基本相象.
  這裏我有個習慣:就是用表的名字+'_'+觸發器類型的縮寫.因此如果是表t26,觸發器是在事件UPDATE(參考下面的點(2)和(3))之前(BEFORE)的,那麼它的名字就是t26_bu。
  2. Syntax: Time 語法:觸發時間

CREATE TRIGGER <觸發器名稱>
{ BEFORE | AFTER } <--
{ INSERT | UPDATE | DELETE }
ON <表名稱>
FOR EACH ROW
<觸發的SQL語句>

  觸發器有執行的時間設置:可以設置爲事件發生前或後。
  3. Syntax: Event語法:事件

CREATE TRIGGER <觸發器名稱>
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE } <--
ON <表名稱>
FOR EACH ROW
<觸發的SQL語句>

  同樣也能設定觸發的事件:它們可以在執行insert、update或delete的過程中觸發。

  4. Syntax: Table 語法:表

CREATE TRIGGER <觸發器名稱>
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON <表名稱> <--
FOR EACH ROW
<觸發的SQL語句>

  觸發器是屬於某一個表的:當在這個表上執行插入、更新或刪除操作的時候就導致觸發器的激活.
我們不能給同一張表的同一個事件安排兩個觸發器。
  5. Syntax: Granularity 語法:( :( 步長)觸發間隔

CREATE TRIGGER <觸發器名稱>
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON <表名稱>
FOR EACH ROW <--
<觸發的SQL語句>

  觸發器的執行間隔:FOR EACH ROW子句通知觸發器每隔一行執行一次動作,而不是對整個表執行一次。
  6. Syntax: Statement 語法:語句

CREATE TRIGGER <觸發器名稱>
{ BEFORE | AFTER }
{ INSERT | UPDATE | DELETE }
ON <表名稱>
FOR EACH ROW
<觸發的SQL語句> <--

  觸發器包含所要觸發的SQL語句:這裏的語句可以是任何合法的語句,包括複合語句,但是這裏的語句受的限制和函數的一樣。

Privileges權限
  你必須擁有相當大的權限才能創建觸發器(CREATE TRIGGER)。如果你已經是Root用戶,那麼就足夠了。這跟SQL的標準有所不同,我也希望能儘快改成標準的。
  因此在下一個版本的MySQL中,你完全有可能看到有一種叫做CREATE TRIGGER的新權限。然後通過這樣的方法賦予:

GRANT CREATE TRIGGER ON <表名稱> TO <用戶或用戶列表>;

  也可以通過這樣收回權限:

REVOKE CREATE TRIGGER ON <表名稱> FROM <用戶或用戶列表>;

Referring to OLD and NEW columns 關於舊的和新創建的列的標識
  在觸發器的SQL語句中,你可以關聯表中的任意列。但你不能僅使用列的名稱去標識,那會使系統混淆,因爲那裏可能會有列的新名(這可能正是你要修改的,你的動作可能正是要修改列名),還有列的舊名存在。因此你必須用這樣的語法來標識:
  "NEW . column_name"或者"OLD . column_name".這樣在技術上處理(NEW | OLD . column_name)新和舊的列名屬於創建了過渡變量("transition variables")。
  對於INSERT語句,只有NEW是合法的;對於DELETE語句,只有OLD才合法;而UPDATE語句可以在和NEW以及OLD同時使用。下面是一個UPDATE中同時使用NEW和OLD的例子。

CREATE TRIGGER t21_au
BEFORE UPDATE ON t22
FOR EACH ROW
BEGIN
SET @old = OLD . s1;
SET @new = NEW.s1;
END;//

  現在如果t21表中的s1列的值是55,那麼執行了"UPDATE t21 SET s1 = s1 + 1"之後@old的值會變成55,而@new的值將會變成56。

Example of CREATE and INSERT CREATE和INSERT的例子
  CREATE table with trigger創建有觸發器的表
  這裏所有的例程中我都假定大家的分隔符已經設置成//(DELIMITER //)。

CREATE TABLE t22 (s1 INTEGER)//
CREATE TRIGGER t22_bi
BEFORE INSERT ON t22
FOR EACH ROW
BEGIN
SET @x = 'Trigger was activated!';
SET NEW.s1 = 55;
END;//

  在最開始我創建了一個名字爲t22的表,然後在表t22上創建了一個觸發器t22_bi,當我們要向表中的行插入時,觸發器就會被激活,執行將s1列的值改爲55的動作。
  INSERT on table w ith a trigger使用觸發器執行插入動作

mysql> INSERT INTO t22 VALUES (1)//

  讓我們看如果向表t2中插入一行數據觸發器對應的表會怎麼樣?
  這裏的插入的動作是很常見的,我們不需要觸發器的權限來執行它。甚至不需要知道是否有觸發器關聯。

mysql> SELECT @x, t22.* FROM t22//
+------------------------+------+
| @x | s1 |
+------------------------+------+
| Trigger was activated! | 55 |
+------------------------+------+
1 row in set (0.00 sec)

  大家可以看到INSERT動作之後的結果,和我們預期的一樣,x標記被改動了,同時這裏插入的數據不是我們開始輸入的插入數據,而是觸發器自己的數據。

Example of a "check" constraint 
"check"完整性約束例子
  What's a "check" constraint 什麼是"check"約束
  在標準的SQL語言中,我們可以在(CREATE TABLE)創建表的過程中使用"CHECK (condition)",
例如:

CREATE TABLE t25
(s1 INT, s2 CHAR(5), PRIMARY KEY (s1),
CHECK (LEFT(s2,1)='A'))
ENGINE=INNODB;


  這裏CHECK的意思是"當s2列的最左邊的字符不是'A'時,insert和update語句都會非法",MySQL的視圖不支持CHECK,我個人是很希望它能支持的。但如果你很需要在表中使用這樣的功能,我建議大家使用觸發器來實現。

CREATE TABLE t25
(s1 INT, s2 CHAR(5),
PRIMARY KEY (s1))
ENGINE=INNODB//

CREATE TRIGGER t25_bi
BEFORE INSERT ON t25
FOR EACH ROW
IF LEFT(NEW.s2,1)<>'A' THEN SET NEW.s1=0; END IF;//

CREATE TRIGGER t25_bu
BEFORE UPDATE ON t25
FOR EACH ROW
IF LEFT(NEW.s2,1)<>'A' THEN SET NEW.s1=0; END IF;//

  我只需要使用BEFORE INSERT和BEFORE UPDATE語句就行了,刪除了觸發器不會對錶有影響,同時AFTER的觸發器也不能修改NEW的過程變量(transition variables)。爲了激活觸發器,我執行了向表中的行插入s1=0的數據,之後只要執行符合LEFT(s2,1) <> 'A'條件的動作都會失敗:

INSERT INTO t25 VALUES (0,'a') /* priming the pump */ //
INSERT INTO t25 VALUES (5,'b') /* gets error '23000' */ //

發佈了20 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章