时间:2021-07-01 10:21:17 帮助过:52人阅读
约定和编程风格 每次我想要演示实际代码时,我会对mysql客户端的屏幕就出现的代码进行调整,将字体改成Courier,使他们看起来与普通文本不一样(让大家区别程序代码和正文)。在这里举个例子: mysql DROP FUNCTION f;Query OK, 0 rows affected (0.00 sec)
约定和编程风格如果实例比较大,则需要在某些行和段落间加注释,同时我会用将"<--"符号放在页面的右边以表示强调。例如:
- mysql> DROP FUNCTION f;
- Query OK, 0 rows affected (0.00 sec)
有时候我会将例子中的"mysql>"和"->"这些系统显示去掉,你可以直接将代码复制到mysql客户端程序中(如果你现在所读的不是电子版的,可以在mysql.com网站下载相关脚本) 所以的例子都已经在Suse 9.2 Linux、Mysql 5.0.3公共版上测试通过。在您阅读本书的时候,Mysql已经有更高的版本,同时能支持更多OS了,包括Windows,Sparc,HP-UX。因此这里的例子将能正常的运行在您的电脑上。但如果运行仍然出现故障,可以咨询你认识的资深Mysql用户,这样就能得到比较好的支持和帮助。
- mysql> CREATE PROCEDURE p ()
- -> BEGIN
- -> /* This procedure does nothing */ <--
- -> END;//
- Query OK, 0 rows affected (0.00 sec)
在这里我假定大家都读过"MySQL新特性"丛书的第一集--"MySQL存储过程",那么大家都应该知道MySQL至此存储过程和函数,那是很重要的知识,因为在触发器中你可以使用在函数中使用的语句。特别举个例子:
- MySQL早期版本的用户长期有需要触发器的要求。
- 我们曾经许诺支持所有ANSI标准的特性。
- 您可以使用它来检查或预防坏的数据进入数据库。
- 您可以改变或者取消INSERT, UPDATE以及DELETE语句。
- 您可以在一个会话中监视数据改变的动作。
触发器相对而言比较新,因此会有(bugs)缺陷.所以我在这里给大家警告,就像我在存储过程书中所说那样.不要在含有重要数据的数据库中使用这个触发器,如果需要的话在一些以测试为目的的数据库上使用,同时在你对表创建触发器时确认这些数据库是默认的。
- 复合语句(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
- 在触发器中也有完全一样的限制.
触发器必须有名字,最多64个字符,可能后面会附有分隔符.它和MySQL中其他对象的命名方式基本相象.
- 1. 语法:命名规则
- CREATE TRIGGER <触发器名称> <--
- { BEFORE | AFTER }
- { INSERT | UPDATE | DELETE }
- ON <表名称>
- FOR EACH ROW
- <触发器SQL语句>
关于旧的和新创建的列的标识
- 2. 语法:触发时间
- CREATE TRIGGER <触发器名称>
- { BEFORE | AFTER } <--
- { INSERT | UPDATE | DELETE }
- ON <表名称>
- FOR EACH ROW
- <触发的SQL语句>
- 触发器有执行的时间设置:可以设置为事件发生前或后。
- 3. 语法:事件
- CREATE TRIGGER <触发器名称>
- { BEFORE | AFTER }
- { INSERT | UPDATE | DELETE } <--
- ON <表名称>
- FOR EACH ROW
- <触发的SQL语句>
- 同样也能设定触发的事件:它们可以在执行insert、update或delete的过程中触发。
- 4. 语法:表
- CREATE TRIGGER <触发器名称>
- { BEFORE | AFTER }
- { INSERT | UPDATE | DELETE }
- ON <表名称> <--
- FOR EACH ROW
- <触发的SQL语句>
- 触发器是属于某一个表的:当在这个表上执行插入、
- 更新或删除操作的时候就导致触发器的激活.
- 我们不能给同一张表的同一个事件安排两个触发器。
- 5. 语法:( 步长)触发间隔
- CREATE TRIGGER <触发器名称>
- { BEFORE | AFTER }
- { INSERT | UPDATE | DELETE }
- ON <表名称>
- FOR EACH ROW <--
- <触发的SQL语句>
- 触发器的执行间隔:FOR EACH ROW子句通知触发器
- 每隔一行执行一次动作,而不是对整个表执行一次。
- 6. 语法:语句
- 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 <用户或用户列表>;
- 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。
在最开始我创建了一个名字为t22的表,然后在表t22上创建了一个触发器t22_bi,当我们要向表中的行插入时,触发器就会被激活,执行将s1列的值改为55的动作。
- Example of CREATE and INSERT CREATE和INSERT的例子
- 创建有触发器的表
- 这里所有的例程中我都假定大家的分隔符已经设置成//(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;//
大家可以看到INSERT动作之后的结果,和我们预期的一样,x标记被改动了,同时这里插入的数据不是我们开始输入的插入数据,而是触发器自己的数据。
- mysql> SELECT @x, t22.* FROM t22//
- +------------------------+------+
- | @x | s1 |
- +------------------------+------+
- | Trigger was activated! | 55 |
- +------------------------+------+
- 1 row in set (0.00 sec)
这里CHECK的意思是"当s2列的最左边的字符不是'A'时,insert和update语句都会非法",MySQL的视图不支持CHECK,我个人是很希望它能支持的。但如果你很需要在表中使用这样的功能,我建议大家使用触发器来实现。
- "check"完整性约束例子
- 什么是"check"约束
- 在标准的SQL语言中,我们可以在(CREATE TABLE)创建表的过程中使用"CHECK (condition)",
- 例如:
- CREATE TABLE t25
- (s1 INT, s2 CHAR(5), PRIMARY KEY (s1),
- CHECK (LEFT(s2,1)='A'))
- ENGINE=INNODB;
我只需要使用BEFORE INSERT和BEFORE UPDATE语句就行了,删除了触发器不会对表有影响,同时AFTER的触发器也不能修改NEW的过程变量(transition variables)。为了激活触发器,我执行了向表中的行插入s1=0的数据,之后只要执行符合LEFT(s2,1) <> 'A'条件的动作都会失败:
- 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;//
该抛弃旧的MySQL的手册了
- INSERT INTO t25 VALUES (0,'a') /* priming the pump */ //
- INSERT INTO t25 VALUES (5,'b') /* gets error '23000' */ //
- Don't Believe The Old MySQL Manual