目录

前言

1. 一般信息

2. 安装MySQL

3. 教程

4. MySQL程序概述

5. 数据库管理

6. MySQL中的复制

7. 优化

8. 客户端和实用工具程序

9. 语言结构

10. 字符集支持

11. 列类型

12. 函数和操作符

13. SQL语句语法

14. 插件式存储引擎体系结构

15. 存储引擎和表类型

16. 编写自定义存储引擎

17. MySQL簇

18. 分区

19. MySQL中的空间扩展

20. 存储程序和函数

21. 触发程序

22. 视图

23. INFORMATION_SCHEMA信息

24. 精度数学

25. API和库

26. 连接器

27. 扩展MySQL

A. 问题和常见错误

B. 错误代码和消息

C. 感谢

D. MySQL变更史

E. 移植到其他系统

F. 环境变量

G. MySQL正则表达式

H. MySQL中的限制

I. 特性限制

J. GNU通用公共许可

K. MySQL FLOSS许可例外

索引

第21章:触发程序

MySQL 5.1包含对触发程序的支持。触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象。例如,下述语句将创建1个表和1INSERT触发程序。触发程序将插入表中某一列的值加在一起:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;

在本章中,介绍了创建和撤销触发程序的语法,并给出了一些使用它们的示例。关于对触发程序使用的限制,请参见附录I:特性限制

关于触发程序的二进制日志功能,请参见20.4节,“存储子程序和触发程序的二进制日志功能”

21.1. CREATE TRIGGER语法

CREATE TRIGGER trigger_name trigger_time trigger_event
    ON tbl_name FOR EACH ROW trigger_stmt

触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象。

触发程序与命名为tbl_name的表相关。tbl_name必须引用永久性表。不能将触发程序与TEMPORARY表或视图关联起来。

trigger_time是触发程序的动作时间。它可以是BEFOREAFTER,以指明触发程序是在激活它的语句之前或之后触发。

trigger_event指明了激活触发程序的语句的类型。trigger_event可以是下述值之一:

·         INSERT:将新行插入表时激活触发程序,例如,通过INSERTLOAD DATAREPLACE语句。

·         UPDATE:更改某一行时激活触发程序,例如,通过UPDATE语句。

·         DELETE:从表中删除某一行时激活触发程序,例如,通过DELETEREPLACE语句。

请注意,trigger_event与以表操作方式激活触发程序的SQL语句并不很类似,这点很重要。例如,关于INSERTBEFORE触发程序不仅能被INSERT语句激活,也能被LOAD DATA语句激活。

可能会造成混淆的例子之一是INSERT INTO .. ON DUPLICATE UPDATE ...语法:BEFORE INSERT触发程序对于每一行将激活,后跟AFTER INSERT触发程序,或BEFORE UPDATEAFTER UPDATE触发程序,具体情况取决于行上是否有重复键。

对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。例如,对于某一表,不能有两个BEFORE UPDATE触发程序。但可以有1BEFORE UPDATE触发程序和1BEFORE INSERT触发程序,或1BEFORE UPDATE触发程序和1AFTER UPDATE触发程序。

trigger_stmt是当触发程序激活时执行的语句。如果你打算执行多个语句,可使用BEGIN ... END复合语句结构。这样,就能使用存储子程序中允许的相同语句。请参见20.2.7节,“BEGIN ... END复合语句”

MySQL 5.1中,可以编写包含按名称对表进行直接引用的触发程序,如下例中所示的名为testref的触发程序:

CREATE TABLE test1(a1 INT);
CREATE TABLE test2(a2 INT);
CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE test4(
  a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  b4 INT DEFAULT 0
);
 
DELIMITER |
 
CREATE TRIGGER testref BEFORE INSERT ON test1
  FOR EACH ROW BEGIN
    INSERT INTO test2 SET a2 = NEW.a1;
    DELETE FROM test3 WHERE a3 = NEW.a1;  
    UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
  END
|
 
DELIMITER ;
 
INSERT INTO test3 (a3) VALUES 
  (NULL), (NULL), (NULL), (NULL), (NULL), 
  (NULL), (NULL), (NULL), (NULL), (NULL);
 
INSERT INTO test4 (a4) VALUES 
  (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);

如果将下述值插入表test1,如下所示:

mysql> INSERT INTO test1 VALUES 
    -> (1), (3), (1), (7), (1), (8), (4), (4);
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

那么4个表中的数据如下:

mysql> SELECT * FROM test1;
+------+
| a1   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)
 
mysql> SELECT * FROM test2;
+------+
| a2   |
+------+
|    1 |
|    3 |
|    1 |
|    7 |
|    1 |
|    8 |
|    4 |
|    4 |
+------+
8 rows in set (0.00 sec)
 
mysql> SELECT * FROM test3;
+----+
| a3 |
+----+
|  2 |
|  5 |
|  6 |
|  9 |
| 10 |
+----+
5 rows in set (0.00 sec)
 
mysql> SELECT * FROM test4;
+----+------+
| a4 | b4   |
+----+------+
|  1 |    3 |
|  2 |    0 |
|  3 |    1 |
|  4 |    2 |
|  5 |    0 |
|  6 |    0 |
|  7 |    1 |
|  8 |    1 |
|  9 |    0 |
| 10 |    0 |
+----+------+
10 rows in set (0.00 sec)

使用别名OLDNEW,能够引用与触发程序相关的表中的列。OLD.col_name在更新或删除它之前,引用已有行中的1列。NEW.col_name在更新它之后引用将要插入的新行的1列或已有行的1列。

激活触发程序时,对于触发程序引用的所有OLDNEW列,需要具有SELECT权限,对于作为SET赋值目标的所有NEW列,需要具有UPDATE权限。

注释:目前,触发程序不会被级联的 外键动作激活。该限制将会被尽早放宽。

CREATE TRIGGER语句需要SUPER权限。

21.2. DROP TRIGGER语法

DROP TRIGGER [schema_name.]trigger_name

舍弃触发程序。方案名称(schema_name)是可选的。如果省略了schema(方案),将从当前方案中舍弃触发程序。

注释:MySQL 5.0.10之前的MySQL版本升级到5.0.10或更高版本时(包括所有的MySQL 5.1版本),必须在升级之前舍弃所有的触发程序,并在随后重新创建它们,否则,在升级之后DROP TRIGGER不工作。关于推荐的升级步骤,请参见2.10.1节,“从5.0版升级”

DROP TRIGGER语句需要SUPER权限。

21.3. 使用触发程序

在本节中,介绍了在MySQL 5.1中使用触发程序的方法,并介绍了在使用触发程序方面的限制。

触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象。在某些触发程序的用法中,可用于检查插入到表中的值,或对更新涉及的值进行计算。

触发程序与表相关,当对表执行INSERTDELETEUPDATE语句时,将激活触发程序。可以将触发程序设置为在执行语句之前或之后激活。例如,可以在从表中删除每一行之前,或在更新了每一行后激活触发程序。

要想创建触发程序或舍弃触发程序,可使用CREATE TRIGGERDROP TRIGGER语句。关于这些语句的语法,请参见21.1节,“CREATE TRIGGER语法”21.2节,“DROP TRIGGER语法”

下面给出了1个简单的示例,在该示例中,针对INSERT语句,将触发程序和表关联了起来。其作用相当于累加器,能够将插入表中某一列的值加起来。

在下面的语句中,创建了1个表,并为表创建了1个触发程序:

mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
    -> FOR EACH ROW SET @sum = @sum + NEW.amount;

CREATE TRIGGER语句创建了与账户表相关的、名为ins_sum的触发程序。它还包括一些子句,这些子句指定了触发程序激活时间、触发程序事件、以及激活触发程序时作些什么:

·         关键字BEFORE指明了触发程序的动作时间。在本例中,应在将每一行插入表之前激活触发程序。这类允许的其他关键字是AFTER

·         关键字INSERT指明了激活触发程序的事件。在本例中,INSERT语句将导致触发程序的激活。你也可以为DELETEUPDATE语句创建触发程序。

·         跟在FOR EACH ROW后面的语句定义了每次激活触发程序时将执行的程序,对于受触发语句影响的每一行执行一次。在本例中,触发的语句是简单的SET语句,负责将插入amount列的值加起来。该语句将列引用为NEW.amount,意思是将要插入到新行的amount列的值

要想使用触发程序,将累加器变量设置为0,执行INSERT语句,然后查看变量的值:

mysql> SET @sum = 0;
mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
mysql> SELECT @sum AS 'Total amount inserted';
+-----------------------+
| Total amount inserted |
+-----------------------+
| 1852.48               |
+-----------------------+

在本例中,执行了INSERT语句后,@sum的值是14.98 + 1937.50 – 1001852.48

要想销毁触发程序,可使用DROP TRIGGER语句。如果触发程序不在默认的方案中,必须指定方案名称:

mysql> DROP TRIGGER test.ins_sum;

触发程序名称存在于方案的名称空间内,这意味着,在1个方案中,所有的触发程序必须具有唯一的名称。位于不同方案中的触发程序可以具有相同的名称。

1个方案中,所有的触发程序名称必须是唯一的,除了该要求外,对于能够创建的触发程序的类型还存在其他限制。尤其是,对于具有相同触发时间和触发事件的表,不能有2个触发程序。例如,不能为某一表定义2BEFORE INSERT触发程序或2AFTER UPDATE触发程序。这几乎不是有意义的限制,这是因为,通过在FOR EACH ROW之后使用BEGIN ... END复合语句结构,能够定义执行多条语句的触发程序。请参见本节后面给出的示例。

此外,激活触发程序时,对触发程序执行的语句也存在一些限制:

·         触发程序不能调用将数据返回客户端的存储程序,也不能使用采用CALL语句的动态SQL(允许存储程序通过参数将数据返回触发程序)。

·         触发程序不能使用以显式或隐式方式开始或结束事务的语句,如START TRANSACTIONCOMMITROLLBACK

使用OLDNEW关键字,能够访问受触发程序影响的行中的列(OLDNEW不区分大小写)。在INSERT触发程序中,仅能使用NEW.col_name,没有旧行。在DELETE触发程序中,仅能使用OLD.col_name,没有新行。在UPDATE触发程序中,可以使用OLD.col_name来引用更新前的某一行的列,也能使用NEW.col_name来引用更新后的行中的列。

OLD命名的列是只读的。你可以引用它,但不能更改它。对于用NEW命名的列,如果具有SELECT权限,可引用它。在BEFORE触发程序中,如果你具有UPDATE权限,可使用“SET NEW.col_name = value更改它的值。这意味着,你可以使用触发程序来更改将要插入到新行中的值,或用于更新行的值。

BEFORE触发程序中,AUTO_INCREMENT列的NEW0,不是实际插入新记录时将自动生成的序列号。

OLDNEW是对触发程序的MySQL扩展。

通过使用BEGIN ... END结构,能够定义执行多条语句的触发程序。在BEGIN块中,还能使用存储子程序中允许的其他语法,如条件和循环等。但是,正如存储子程序那样,定义执行多条语句的触发程序时,如果使用mysql程序来输入触发程序,需要重新定义语句分隔符,以便能够在触发程序定义中使用字符“;”。在下面的示例中,演示了这些要点。在该示例中,定义了1UPDATE触发程序,用于检查更新每一行时将使用的新值,并更改值,使之位于0100的范围内。它必须是BEFORE触发程序,这是因为,需要在将值用于更新行之前对其进行检查:

mysql> delimiter //
mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
    -> FOR EACH ROW
    -> BEGIN
    ->     IF NEW.amount < 0 THEN
    ->         SET NEW.amount = 0;
    ->     ELSEIF NEW.amount > 100 THEN
    ->         SET NEW.amount = 100;
    ->     END IF;
    -> END;//
mysql> delimiter ;

较为简单的方法是,单独定义存储程序,然后使用简单的CALL语句从触发程序调用存储程序。如果你打算从数个触发程序内部调用相同的子程序,该方法也很有帮助。

在触发程序的执行过程中,MySQL处理错误的方式如下:

·         如果BEFORE触发程序失败,不执行相应行上的操作。

·         仅当BEFORE触发程序(如果有的话)和行操作均已成功执行,才执行AFTER触发程序。

·         如果在BEFOREAFTER触发程序的执行过程中出现错误,将导致调用触发程序的整个语句的失败。

·         对于事务性表,如果触发程序失败(以及由此导致的整个语句的失败),该语句所执行的所有更改将回滚。对于非事务性表,不能执行这类回滚,因而,即使语句失败,失败之前所作的任何更改依然有效。


这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问dev.mysql.com。原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。


This file is decompiled by an unregistered version of ChmDecompiler.
Regsitered version does not show this message.
You can download ChmDecompiler at : http://www.etextwizard.com/