本章讨论存储的程序和视图,这些数据库对象是根据存储在服务器上供以后执行的SQL代码定义的数据库对象。
存储的程序包括这些对象:
CALL
语句调用存储过程 。过程没有返回值,但可以修改其参数供调用者稍后检查。它也可以生成返回给客户端程序的结果集。存储的功能与内置功能非常相似。您可以在表达式中调用它并在表达式评估期间返回一个值。视图是被存储的查询,当被引用时产生结果集。视图充当虚拟表格。
每个存储的程序都包含一个由SQL语句组成的主体。该语句可能是一个复合语句,由多个由;
字符分隔的语句组成。例如,以下的存储过程的主体由一个BEGIN...END
包含SET
语句的块和一个REPEAT
本身包含另一个SET
语句的循环组成。:
CREATE PROCEDURE dorepeat(p1 INT)
BEGIN
SET @x = 0;
REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
END;
默认情况下delimiter
使用;
分隔语句,MySQL
遇到;
号就执行对应的SQL语句。可以使用delimiter
重新定义分隔符,通常我们定义为//
或者$$
。
delimiter //
CREATE PROCEDURE dorepeat(p1 INT)
BEGIN
SET @x = 0;
REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
END
//
存储的例程是一组可存储在服务器中的SQL语句。完成此操作后,客户端不需要重新发布单个语句,而是可以引用存储的例程。
存储的例程在某些情况下特别有用:
存储的例程还使您能够在数据库服务器中拥有函数库。这是现代应用程序语言所共有的一项功能,可在内部启用此类设计(例如,通过使用类)。即使在数据库使用范围之外,使用这些客户端应用程序语言功能对程序员也是有益的。
过程
函数
使用CALL
语句调用过程。
函数不能递归,过程允许递归但默认情况是禁用的。要启动递归,需要将max_sp_recursion_depth
服务器系统变量设置为大于零的值。存储过程递归增加了对线程堆栈空间的需求。如果增加值max_sp_recursion_depth
,可能需要通过增加thread_stack
服务器启动时的值来增加线程堆栈大小。
触发器是一个与表关联的命名数据库对象,当表发生特定事件时会激活该对象。触发器的一些用途是执行要插入到表中的值的检查或对更新中涉及的值执行计算。
触发器定义为在语句插入,更新或删除关联表中的行时激活。这些行操作是触发事件。例如,可以通过 INSERT
或LOAD DATA
语句插入行,并为每个插入的行激活插入触发器。触发器可以设置为在触发事件之前或之后激活。例如,可以在插入表的每一行之前或每更新一行之后激活触发器。
创建触发器:CREATE TRIGGER
。
删除触发器:DROP TRIGGER
,删除数据库表时触发器也会被一并删除。
下面是一个简单的例子,它将一个触发器与一个表相关联,以激活INSERT
操作。触发器充当累加器,将插入到表格的其中一列中的值相加。
mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
Query OK, 0 rows affected (0.03 sec)
mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
FOR EACH ROW SET @sum = @sum + NEW.amount;
Query OK, 0 rows affected (0.01 sec)
该CREATE TRIGGER
语句创建一个名为ins_sum
与account
表关联的触发器。它还包括指定触发器动作时间,触发事件以及触发器激活时要执行的操作的子句:
BEFORE
指示触发器动作时间。在这种情况下,触发器会在每行插入表之前激活。这里另一个允许的关键字是AFTER
。INSERT
表示触发事件; 即激活触发器的操作类型。在该示例中,INSERT
操作会导致触发器激活。您也可以创建触发器DELETE
和 UPDATE
操作。FOR EACH ROW
定义了触发器主体; 即每次触发器激活时要执行的语句,对于受触发事件影响的每一行都会发生一次。在该示例中,触发器主体很简单 SET
,它将插入到amount
列中的值累加到用户变量中。该语句引用该列NEW.amount
意味着 “ 要插入到新行中的amount
列的值。”要使用触发器,请将累加器变量设置为零,执行INSERT
语句,然后查看该变量后面的值:
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 |
+-----------------------+