1. 程式人生 > 實用技巧 >MySQL教程114-MySQL建立觸發器

MySQL教程114-MySQL建立觸發器

觸發器是與MySQL資料表有關的資料庫物件,在滿足定義條件時觸發,並執行觸發器中定義的語句集合。觸發器的這種特性可以協助應用在資料庫端確保資料的完整性。

基本語法

CREATE TRIGGER <觸發器名> {BEFORE | AFTER} {INSERT | UPDATE | DELETE } ON <表名> FOR EACH ROW <觸發器主體>

語法說明如下。

1) 觸發器名

觸發器的名稱,觸發器在當前資料庫中必須具有唯一的名稱。如果要在某個特定資料庫中建立,名稱前面應該加上資料庫的名稱。

2) INSERT | UPDATE | DELETE

觸發事件,用於指定啟用觸發器的語句的種類。

注意:三種觸發器的執行時間如下。

  • INSERT:將新行插入表時啟用觸發器。例如,INSERT 的 BEFORE 觸發器不僅能被 MySQL 的 INSERT 語句啟用,也能被 LOAD DATA 語句啟用。
  • DELETE: 從表中刪除某一行資料時啟用觸發器,例如 DELETE 和 REPLACE 語句。
  • UPDATE:更改表中某一行資料時啟用觸發器,例如 UPDATE 語句。

3) BEFORE | AFTER

BEFORE 和 AFTER,觸發器被觸發的時刻,表示觸發器是在啟用它的語句之前或之後觸發。若希望驗證新資料是否滿足條件,則使用 BEFORE 選項;若希望在啟用觸發器的語句執行之後完成幾個或更多的改變,則通常使用 AFTER 選項。

4) 表名

與觸發器相關聯的表名,此表必須是永久性表,不能將觸發器與臨時表或檢視關聯起來。在該表上觸發事件發生時才會啟用觸發器。同一個表不能擁有兩個具有相同觸發時刻和事件的觸發器。例如,對於一張資料表,不能同時有兩個 BEFORE UPDATE 觸發器,但可以有一個 BEFORE UPDATE 觸發器和一個 BEFORE INSERT 觸發器,或一個 BEFORE UPDATE 觸發器和一個 AFTER UPDATE 觸發器。

5) 觸發器主體

觸發器動作主體,包含觸發器啟用時將要執行的 MySQL 語句。如果要執行多個語句,可使用 BEGIN…END 複合語句結構。

6) FOR EACH ROW

一般是指行級觸發,對於受觸發事件影響的每一行都要啟用觸發器的動作。例如,使用 INSERT 語句向某個表中插入多行資料時,觸發器會對每一行資料的插入都執行相應的觸發器動作。

注意:每個表都支援 INSERTUPDATEDELETE 的 BEFORE 與 AFTER,因此每個表最多支援 6 個觸發器。每個表的每個事件每次只允許有一個觸發器。單一觸發器不能與多個事件或多個表關聯。

另外,在 MySQL 中,若需要檢視資料庫中已有的觸發器,則可以使用 SHOW TRIGGERS 語句。

建立 BEFORE 型別觸發器

在 test_db 資料庫中,資料表 tb_emp8 為員工資訊表,包含 id、name、deptId 和 salary 欄位,資料表 tb_emp8 的表結構如下所示。

mysql> desc tb_emp8;
+--------+-------------+------+-----+---------+----------------+
| Field  | Type        | Null | Key | Default | Extra          |
+--------+-------------+------+-----+---------+----------------+
| id     | int(11)     | NO   | PRI | NULL    | auto_increment |
| name   | varchar(25) | YES  | UNI | NULL    |                |
| deptId | int(11)     | NO   | MUL | NULL    |                |
| salary | float       | YES  |     | NULL    |                |
+--------+-------------+------+-----+---------+----------------+
4 rows in set (0.06 sec)

mysql> select * from tb_emp8;
Empty set (0.02 sec)

【例項 1】建立一個名為 SumOfSalary 的觸發器,觸發的條件是向資料表 tb_emp8 中插入資料之前,對新插入的 salary 欄位值進行求和計算。輸入的 SQL 語句和執行過程如下所示。

mysql> \. E:\java\mysql\my.sql
Query OK, 0 rows affected (0.10 sec)

my.sql檔案內容如下:

delimiter //
set @sum = 0;
create trigger SumOfSalary
before insert on tb_emp8 
for each row 
begin
    set @sum = @sum + new.salary;
end//
delimiter ;

注意, 這裡的會話變數@sum是在觸發器建立之前中定義的, 也就是說每次刪除重新執行my.sql的話, @sum的值都會變成0, 如果不刪除, @sum的值就會一直累加...
因為tb_emp8中還沒有資料, 所以累加salary的話, 就是從每次insert中的new中獲取salary累加

觸發器 SumOfSalary 建立完成之後,向表 tb_emp8 中插入記錄時,定義的 sum 值由 0 變成了 1500,即插入值 1000 和 500 的和,如下所示。

mysql> insert into tb_emp8 values (null, 'test1', 1, 1000);
Query OK, 1 row affected (0.09 sec)

mysql> select @sum;
+------+
| @sum |
+------+
| 1000 |
+------+
1 row in set (0.00 sec)

mysql> insert into tb_emp8 values (null, 'test2', 1, 500);
Query OK, 1 row affected (0.10 sec)

mysql> select @sum;
+------+
| @sum |
+------+
| 1500 |
+------+
1 row in set (0.00 sec)

上面是在tb_emp8沒資料的情況下, 如果此表已經有資料了, 依然向資料表 tb_emp8 中插入資料之前,對新插入的 salary 欄位值進行求和計算, 出發器如下定義

delimiter //
set @sum = 0;
create trigger SumOfSalary
before insert on tb_emp8 
for each row 
begin
    declare sum1 float;
    select sum(salary) into sum1 from tb_emp8;
    set @sum = sum1 + new.salary;
end//
delimiter ;

建立 AFTER 型別觸發器

在 test_db 資料庫中,資料表 tb_emp6 和 tb_emp7 都為員工資訊表,包含 id、name、deptId 和 salary 欄位,資料表 tb_emp6 和 tb_emp7 的表結構如下所示。

mysql> select * from tb_emp6;
Empty set (0.00 sec)

mysql> select * from tb_emp7;
Empty set (0.00 sec)

mysql> desc tb_emp6;
+--------+-------------+------+-----+---------+----------------+
| Field  | Type        | Null | Key | Default | Extra          |
+--------+-------------+------+-----+---------+----------------+
| id     | int(11)     | NO   | PRI | NULL    | auto_increment |
| name   | varchar(25) | NO   |     | NULL    |                |
| deptId | int(11)     | YES  | MUL | NULL    |                |
| salary | float       | YES  |     | NULL    |                |
+--------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql> desc tb_emp7;
+--------+-------------+------+-----+---------+----------------+
| Field  | Type        | Null | Key | Default | Extra          |
+--------+-------------+------+-----+---------+----------------+
| id     | int(11)     | NO   | PRI | NULL    | auto_increment |
| name   | varchar(25) | NO   | UNI | NULL    |                |
| deptId | int(11)     | YES  | MUL | NULL    |                |
| salary | float       | YES  |     | NULL    |                |
+--------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

【例項 2】建立一個名為 double_salary 的觸發器,觸發的條件是向資料表 tb_emp6 中插入資料之後,再向資料表 tb_emp7 中插入相同的資料,並且 salary 為 tb_emp6 中新插入的 salary 欄位值的 2 倍。輸入的 SQL 語句和執行過程如下所示。

mysql> \.  E:\java\mysql\my.sql
Query OK, 0 rows affected (0.10 sec)

my.sql檔案內容如下:

delimiter //
create trigger double_salary 
before insert on tb_emp6
for each row
begin
    insert into tb_emp7 values (null, new.name, new.deptId, new.salary*2);
end//
delimiter ;

觸發器 double_salary 建立完成之後,向表 tb_emp6 中插入記錄時,同時向表 tb_emp7 中插入相同的記錄,並且 salary 欄位為 tb_emp6 中 salary 欄位值的 2 倍,如下所示。

mysql> insert into tb_emp6 values (null, 'test', 1, 500);
Query OK, 1 row affected (0.08 sec)

mysql> select * from tb_emp6;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | test |      1 |    500 |
+----+------+--------+--------+
1 row in set (0.00 sec)

mysql> select * from tb_emp7;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | test |      1 |   1000 |
+----+------+--------+--------+
1 row in set (0.00 sec)

mysql> insert into tb_emp6 values (null, 'test2', 1, 1500);
Query OK, 1 row affected (0.07 sec)

mysql> select * from tb_emp6;
+----+-------+--------+--------+
| id | name  | deptId | salary |
+----+-------+--------+--------+
|  1 | test  |      1 |    500 |
|  2 | test2 |      1 |   1500 |
+----+-------+--------+--------+
2 rows in set (0.00 sec)

mysql> select * from tb_emp7;
+----+-------+--------+--------+
| id | name  | deptId | salary |
+----+-------+--------+--------+
|  1 | test  |      1 |   1000 |
|  2 | test2 |      1 |   3000 |
+----+-------+--------+--------+
2 rows in set (0.00 sec)