存储程序(1)——MYSQL
MySQL支持把几种对象存放在服务器端供以后使用。这几种对象有一些可以根据情况通过程序代码调用,有一些会在数据表被修改时自动执行,还有一些可以在预定时刻自动执行。它们包括以下几种:
1.存储函数(stored function)。返回一个计算结果,该结果可以用在表达式里。
2.存储过程(stored procedure)。不直接返回一个结果,但可以用来完成一般的运算或是生成一个结果集并传递回客户。
3.触发器(trigger)。与数据表相关联,当那个数据表被工NSERT、DELETE或UPDATE语句修改时,触发器将自动执行。
4.事件(event)。根据时间表在预定时刻自动执行。
MySQL对存储函数和存储过程的支持始于5.0.0版本,对触发器和事件的支持分别始于5.0.2版本和5.1.6版本。存储程序有以下优点和能力:
1.存储程序对象的可执行部分可以用复合语句来编写,复合语句对SQL语法进行了扩展,可以包括代码块、循环和条件语句。
2.存储程序都被保存在服务器端,定义它们所需要的代码只需在它们被创建时通过网络传递一次,而不是每次执行都要传递一次。这大大减少了开销。
3.它们可以把复杂的计算封装为程序单元,而你可以简单地通过程序单元的名字来调用它们。你甚至可以把一组存储程序打包为一个“函数库”供其他应用程序调用。
4.它们提供了一种错误处理机制。
5.它们可以提高数据库的安全性。你可以通过选择存储程序执行时所需的权限下来对敏感数据的访问情况进行限制和调控。
存储程序。泛指各种类型的存储对象(存储函数、存储过程、触发器、事件)。存储例程(stored routine ),特指存储函数和存储过程。这两种对象的定义语法很相似,所以很自然地把它们放在一起讨论。在开始讨论各种类型的存储程序之前,我们首先学习一下:复合语句。
1.复合语句和语句分隔符
简单的存储程序只包含一条SQL语句,在编写时不需要特殊对待。下面的存储过程使用了一条SELECT语句来列出sampdb数据库里的数据表的名字:
PROCEDURE sampdb_tables()
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA=’sampdb’ ORDER BY TABLE_NAME;
不过,存储程序并非只能包含一条简单的SQL语句。它们可以包含多条SQL语句,可以使用局部变量、条件语句、循环和嵌套语句块等多种语法构造。要使用这些构造编写存储程序,就需要用到复合语句。复合语句由BEGIN开头,END结束,在它们之间可以写出任意数量的语句,这些语句构成了一个语句块。下面的存储过程将显示一条欢迎消息,其中有你的用户名;如果你是一位匿名用户,用户名将是“earthing":
CREATE PROCEDURE greetings()
BEGIN
#77=16 for username+60 for hostname+1 for '@'
DECLARE user CHAR(77) CHARACTER SET utf8;
SET user = (SELECT CURRENT USER());
IF INSTR(user,’@’)>0 THEN
#返回字符串在某一个字段的内容中的位置, 没有找到字符串返回0,否则返回位置(从1开始)
SET user=SUBSTRING_INDEX(user, '@', 1);
END IF;
IF user = '' THEN
SET user='earthling';
END IF;
SELECT CONCAT('Greetings,',user, '!') AS greeting;
END;
在使用复合语句时,必须考虑和解决这样一个问题:复合语句块里的语句必须以分号(;)彼此隔开,但因为分号同时也是mysql程序默认使用的语句分隔符,所以在使用mysql程序定义存储程序时会发生冲突。
解决这个问题的办法是使用delimiter命令把mysql程序的语句分隔符重定义为另一个字符或字符串,它必须是在存储例程的定义里没有出现过的。这样一来,mysql程序就不会把分号解释为语句终止符了,它将把整个对象定义作为一条语句传递给服务器。在定义完存储程序之后,可以把mysql程序的语句终止符重新定义为分号。
use weibo;
delimiter $
CREATE PROCEDURE show_times()
BEGIN
SELECT 'Local time is:', CURRENT_TIMESTAMP;
SELECT 'UTC time is:', UTC_TIMESTAMP;
END$
delimiter ;-- delimiter后空格加分号,将分号设置为分隔符
CALL show_times();
定义一个存储过程时把mysql程序的默认分隔符临时改变为$,然后在恢复了mysql程序的默认分隔符之后执行了那个存储过程:

分隔符不必非得是$字符,也不必非得是单个的字符:
delimiter EOF
这里的原则是:只要在某个存储程序内部的语句里会用到分号,就应该在定义这个存储程序时临时改变mysql程序的分隔符。
2.存储函数和存储过程
存储函数将向调用者返回一个计算结果,这个结果可以用在表达式里(就像COS()或HEX()这样的内建函数那样)。存储过程需要使用CALL语句来调用,是一个独立的操作,不能用在表达式里。使用存储过程的情况主要有两种:(1)只需通过运算来实现某种效果或动作而无需返回一个值,(2)运算会返回多个结果集(函数做不到这一点)。这只是些指导性建议,不是硬性规定。
比如说,如果你需要返回两个或更多的值,就不能使用函数。但你可以使用一个过程,因为过程支持的参数类型允许它们的值在过程执行期间被设置,而调用者可以在过程返回后去访问那些值。
存储函数要用CREATE FUNCTION语句来创建,存储过程要用CREATE PROCEDURE语句来创建。下面的例子将创建一个函数,该函数有一个代表着年份的整数参数。(为了与数据表或数据列的名字有所区别,参数命名时将使用p_前缀)。
delimiter $
CREATE FUNCTION count_born_in_year(p_year INT)
RETURNS INT
READS SQL DATA
BEGIN
RETURN (SELECT COUNT(*) FROM president WHERE YEAR(birtb) = p_year);
END$
delimiter ;
这个函数有一条用来表明其返回值数据类型的RETURNS子句和一个用来计算那个值的函数体。函数体至少需要包含一条RETURN语句,用来向调用者返回一个值。把计算定义为函数的好处是可以方便地执行它而无须每次都写出所有的逻辑,你可以像使用内建函数那样来调用存储函数:
SELECT count_born_in_year(1990);
你无法让一个给定的函数返回多个值。你可以编写任意多个函数,然后在同一条语句里调用它们全体。另一个办法是使用一个存储过程并通过它的OUT参数“返回”多个值。存储过程负责计算那些值并把它们赋值给相应的参数,而那些参数可以在过程返回后由调用者访问。如果你定义了一个与某个MySQL内建函数同名的存储函数,在调用它时就必须用数据库的名字对该函数的名字进行限定以避免歧义。
存储过程和存储函数很相似,但它不返回值。因此,它没有RETURNS子句或任何RETURN语句。下面这个简单的存储过程和count_born_in_year()函数很相似,它将显示一个结果集而不是把计算结果作为其返回值。
delimiter $
CREATE PROCEDURE show_born_in_year(p_year INT)
BEGIN
SELECT first_name, last_name, birth, death
FROM president
WHERE YEAR(birth)=P_year;
END$
delimiter ;
与存储函数不同,存储过程不能用在表达式里,它们只能通过CALL语句来调用。如下所示:
CALL show_born_in_year(1990);
前面的例子都是选取信息,但存储例程还可以用来修改数据表,如下例所示:
delimiter $
CREATE PROCEDURE update_expiration (p_id INT UNSIGNED, p_date DATE)
BEGIN
UPDATE member SET expiration=p_date WHERE member_id=p_id;
END$
delimiter ;
存储函数必须遵守这样一条限制:不允许对调用本函数的语句正在读或写的数据表进行修改。存储过程通常没有这个限制,但如果它们是从存储函数里被调用,就需要遵守这条限制。
3.存储函数和存储过程的权限
存储函数和存储过程属于数据库。要想创建存储函数或存储过程,必须拥有那个数据库的CREATE ROUTINE权限。在默认的情况下,当你创建一个存储例程时,服务器将自动地把EXECUTE和ALTER ROUTINE权限授予你(如果你还没有获得这些权限),这样你才可以执行那个例程或删除它。当你删除那个例程时,服务器将自动撤销那些权限。如果你不想使用这种自动化的权限授予/撤销机制,把automatic_sp_privileges系统变量设置为0即可。
如果服务器启用了二进制日志功能,存储函数还需要遵守一些额外的限制条件(不允许创建不确定或是会修改数据的存储函数)以保证二进制日志能够安全地完成备份和复制操作。这些限制条件如下:
1.如果log_bin_trust_function_creators系统变量没有被激活,你就必须具备SUPER权限才能创建存储函数。在此前提下,你创建的每一个函数都必须是确定的,并且不得修改数据。为了表明这一点,需要使用DETERMINISTIC、NO SQL或READS SQL DATA之一来定义存储函数。
2.如果log bin_trust_function_creators系统变量已被激活,则没有任何限制。只有当你可以相信MySQL服务器上的所有用户都不会去定义不安全的存储函数时,这种设置才是最适当的。
与log_bin_trust_function_creators系统变量有关的限制条件同样适用于触发器的创建工作。
4.存储过程的参数类型
存储过程的参数分为3种类型。对于IN参数,调用者把一个值传递给过程,过程可以对这个值进行修改,但任何修改在过程返回后对调用者是不可见的。OUT参数刚好相反,过程把一个值赋值给OUT参数,这个值在过程返回后可以由调用者访问。INOUT参数允许调用者向过程传递一个值,然后再取回一个值。
要想明确地为参数指定类型,在参数表里把IN, OUT或INOUT写在参数名字前面即可。如果没有为参数指定类型,其默认类型将是IN。
在使用OUT或INOUT参数时,在调用过程时需要给出一个变量名。过程可以设置参数的值,相应的变量将在过程返回时获得那个值。如果想让某个存储过程返回多个结果值,OUT和INOUT参数类型将非常有用(存储函数只能返回一个值,不能胜任)。下面的过程演示了OUT参数的用法。它将分别统计出student数据表里的男生和女生人数并通过它的参数返回这两个计数值,让调用者可以访问它们:
delimiter $
CREATE PROCEDURE count_students_by_sex(OUT p_male INT, OUT p_female INT)
BEGIN
SELECT COUNT(*) FROM student WHERE sex= 'F' INTO p_female;
SELECT COUNT(*) FROM student WHERE sex= 'F' INTO p_female;
END$
delimiter ;
在调用这个过程时,请把各个参数替换为相应的用户定义变量。这个过程将把计数值放到这些参数里,在它返回之后,那些变量将包含计数值:
CALL count_students_by_sex(@mcoant, @fcount);
SELECT 'Number of male students:',@mcount;
IN、OUT和INOUT关键字不适用于存储函数、触发器或事件。对于存储函数,所有的参数都像IN参数。触发器和事件则根本没有任何参数。下一部分介绍:触发器和事件。
存储程序(1)——MYSQL的更多相关文章
- 存储程序(2)——MYSQL
1.触发器 触发器是与特定数据表相关联的存储过程,当相应的数据表被INSERT.DELETE或UPDATE语句修改时,触发器将自动执行.触发器可以被设置成在这几种语句处理每个数据行之前或之后触发.触发 ...
- 阅读MySQL文档第20章:存储程序和函数
本文把阅读到的重点摘抄下来. 一.一个子程序要么是一个程序要么是一个函数.使用CALL语句来调用程序,程序只能用输出变量传回值.就像别其它函数调用一样,函数可以被从语句外调用(即通过引用函数名),函数 ...
- Mysql(三):多表查询和存储程序
今天内容: ● 多表查询(内连接 外连接 子查询) ● 存储程序(存储过程 函数) 多表查询 同时从多张数据表中查取到需要的数据即是多表查询. 多表查询时,参与查询的表中每条数据进行组合,这种效果 ...
- 实战mysql存储程序与定时器
home198979 实战mysql存储程序与定时器 博客分类: mysql 存储过程定时器eventprocedure实战 需求:一个庞大的日志表,现每天做定时统计一天的总数,放另一个表中,方便查 ...
- 数据库之mysql存储程序
什么时候会用到存储过程 1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度2.当对数据库进行复杂操作时 ...
- mysql存储程序
什么时候会用到存储过程 1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度2.当对数据库进行复杂操作时 ...
- Mysql 存储程序
#1存储过程create procedure greeting() BEGIN # 77 = 16 FOR username + 60 for hostname + 1 for '@' DECLARE ...
- 我的MYSQL学习心得(六) 函数
我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(十) 自定义存储过程和函数
我的MYSQL学习心得(十) 自定义存储过程和函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心 ...
随机推荐
- Angular2入门系列教程3-多个组件,主从关系
上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...
- opencv中Mat与IplImage,CVMat类型之间转换
opencv中对图像的处理是最基本的操作,一般的图像类型为IplImage类型,但是当我们对图像进行处理的时候,多数都是对像素矩阵进行处理,所以这三个类型之间的转换会对我们的工作带来便利. Mat类型 ...
- ASP.NET Aries 入门开发教程2:配置出一个简单的列表页面
前言: 朋友们都期待我稳定地工作,但创业公司若要躺下,也非意念可控. 若人生注定了风雨飘摇,那就雨中前行了. 最机开始看聊新的工作机会,欢迎推荐,创业公司也可! 同时,趁着自由时间,抓紧把这系列教程给 ...
- virtualbox linux虚拟机相关
linux虚拟机设置为静态IP 在virtualbox中安装好linux虚拟机后,如果采用的是NAT方式的话,linux虚拟机默认采用dhcp方式自动上网,而且用的是NetworkManager服务而 ...
- Android N开发 你需要知道的一切
title: Android N开发 你需要知道的一切 tags: Android N,Android7.0,Android --- 转载请注明出处:http://www.cnblogs.com/yi ...
- 自己实现一个javascript事件模块
nodejs中的事件模块 nodejs中有一个events模块,用来给别的函数对象提供绑定事件.触发事件的能力.这个别的函数的对象,我把它叫做事件宿主对象(非权威叫法),其原理是把宿主函数的原型链指向 ...
- 实现一个类 RequireJS 的模块加载器 (二)
2017 新年好 ! 新年第一天对我来说真是悲伤 ,早上兴冲冲地爬起来背着书包跑去实验室,结果今天大家都休息 .回宿舍的时候发现书包湿了,原来盒子装的牛奶盖子松了,泼了一书包,电脑风扇口和USB口都进 ...
- SharpMap简析
1.背景 因为项目需求,需要基于开源项目来对SHP进行相关操作.涉及到的主要功能就是加载SHP读取其中的属性信息和几何信息.于是选择了Sharpmap来进行,在使用中对其相关功能做了初步了解,做个总结 ...
- CSS——关于z-index及层叠上下文(stacking context)
以下内容根据CSS规范翻译. z-index 'z-index'Value: auto | <integer> | inheritInitial: autoApplies to: posi ...
- centos 6 安装配置openvpn
下载地址:http://swupdate.openvpn.org/community/releases/http://www.oberhumer.com/opensource/lzo/download ...