在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力。在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用户入门。
存储过程介绍
存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程可由应用程序通过一个调用来执行,而且允许用户声明变量 。同时,存储过程可以接收和输出参数、返回执行存储过程的状态值,也可以嵌套调用。
存储过程的优点
作为存储过程,有以下这些优点:
(1) 减少网络通信量。调用一个行数不多的存储过程与直接调用SQL语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行SQL语句,那么其性能绝对比一条一条的调用SQL语句要高得多。
(2) 执行速度更快。存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接中读取。
(3) 更强的安全性。存储过程是通过向用户授予权限(而不是基于表),它们可以提供对特定数据的访问,提高代码安全,比如防止 SQL注入。
(4) 业务逻辑可以封装存储过程中,这样不仅容易维护,而且执行效率也高
当然存储过程也有一些缺点,比如:
(1) 可移植性方面:当从一种数据库迁移到另外一种数据库时,不少的存储过程的编写要进行部分修改。
(2) 存储过程需要花费一定的学习时间去学习,比如学习其语法等。
在MySQL中,推荐使用MySQL Query Browswer(http://dev.mysql.com/doc/query-browser/en/)这个工具去进行存储过程的开发和管理。下面分步骤来学习MYSQL中的存储过程。
1、定义存储过程的结束符
在存储过程中,通常要输入很多SQL语句,而SQL语句中每个语句以分号来结束,因此要告诉存储过程,什么位置是意味着整个存储过程结束,所以我们在编写存储过程前,先定义分隔符,我们这里定义//为分隔符,我们使用DELIMITER //这样的语法,就可以定义结束符了,当然你可以自己定义其他喜欢的符号。
2、如何创建存储过程
下面先看下一个简单的例子,代码如下:
DELIMITER // CREATEPROCEDURE `p2` () LANGUAGE SQL DETERMINISTIC SQL SECURITY DEFINER COMMENT 'A procedure' BEGIN SELECT'Hello World !'; END//
下面讲解下存储过程的组成部分:
(1). 格式
MySQL存储过程创建的格式:CREATE PROCEDURE 过程名 ([过程参数[,...]])
[特性 ...]过程体
这里先举个例子:
- mysql>
DELIMITER // - mysql>
CREATE PROCEDURE proc1(OUT s int) -
-> BEGIN -
-> SELECT COUNT(*) INTO s FROM user; -
-> END -
-> // - mysql>
DELIMITER ;
注:
(1)这里需要注意的是DELIMITER //和DELIMITER ;两句,DELIMITER是分割符的意思,因为MySQL默认以";"为分隔符,如果我们没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错,所以要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";"当做存储过程中的代码,不会执行这些代码,用完了之后要把分隔符还原。
(2)存储过程根据需要可能会有输入、输出、输入输出参数,这里有一个输出参数s,类型是int型,如果有多个参数用","分割开。
1) 首先在定义好终结符后,使用CREATE PROCEDURE+存储过程名的方法创建存储过程,LANGUAGE选项指定了使用的语言,这里默认是使用SQL。
2) DETERMINISTIC关键词的作用是,当确定每次的存储过程的输入和输出都是相同的内容时,可以使用该关键词,否则默认为NOT DETERMINISTIC。
3) SQL SECURITY关键词,是表示调用时检查用户的权限。当值为INVOKER时,表示是用户调用该存储过程时检查,默认为DEFINER,即创建存储过程时检查。
4) COMMENT部分是存储过程的注释说明部分。
5) 在BEGIN END部分中,是存储过程的主体部分。
变量
Ⅰ. 变量定义
DECLARE variable_name[,variable_name...] datatype [DEFAULT value];其中,datatype为MySQL的数据类型,如:int, float, date,varchar(length)
例如:
- DECLARE
l_int int unsigned default 4000000; - DECLARE
l_numeric number(8,2) DEFAULT 9.95; - DECLARE
l_date date DEFAULT '1999-12-31'; - DECLARE
l_datetime datetime DEFAULT '1999-12-31 23:59:59'; - DECLARE
l_varchar varchar(255) DEFAULT 'This will not be padded';
用户变量
ⅰ. 在MySQL客户端使用用户变量
- mysql
> SELECT 'Hello World' into @x; - mysql
> SELECT @x; - +-------------+
- |
@x | - +-------------+
- |
Hello World | - +-------------+
- mysql
> SET @y='Goodbye Cruel World'; - mysql
> SELECT @y; - +---------------------+
- |
@y | - +---------------------+
- |
Goodbye Cruel World | - +---------------------+
-
- mysql
> SET @z=1+2+3; - mysql
> SELECT @z; - +------+
- |
@z | - +------+
- |
6 | - +------+
ⅱ. 在存储过程中使用用户变量
- mysql
> CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World'); - mysql
> SET @greeting='Hello'; - mysql
> CALL GreetWorld( ); - +----------------------------+
- |
CONCAT(@greeting,' World') | - +----------------------------+
- |
Hello World | - +----------------------------+
- mysql>
CREATE PROCEDURE p1() SET @last_procedure='p1'; - mysql>
CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_proc); - mysql>
CALL p1( ); - mysql>
CALL p2( ); - +-----------------------------------------------+
- |
CONCAT('Last procedure was ',@last_proc | - +-----------------------------------------------+
- |
Last procedure was p1 | - +-----------------------------------------------+
①用户变量名一般以@开头
②滥用用户变量会导致程序难以理解及管理
(5). 注释
MySQL存储过程可使用两种风格的注释
双模杠:--
该风格一般用于单行注释
c风格: 一般用于多行注释
3、调用存储过程的方法
调用存储过程的方法很简单,只需要使用call命令即可,后面跟要调用存储过程的名称及输入的变量列表,比如:
CALL stored_procedure_name (param1, param2, ....) CALL procedure1(10 , 'string parameter' , @parameter_var);
4、修改和删除存储过程
可以用ALTER的语法去修改存储过程的主要特征和参数,要修改其存储过程的主体部分的话,必须要先删除然后再重建。比如下面修改存储过程num_from_employee的定义。将读写权限改为MODIFIES SQL DATA,并指明调用者可以执行。代码执行如下:
ALTER PROCEDURE num_from_employee MODIFIES SQL DATA SQL SECURITY INVOKER ;
而删除存储过程的语法为使用DROP关键词即可。如下
DROP PROCEDURE IF EXISTS p2;
MySQL存储过程的查询
我们像知道一个数据库下面有那些表,我们一般采用showtables;进行查看。那么我们要查看某个数据库下面的存储过程,是否也可以采用呢?答案是,我们可以查看某个数据库下面的存储过程,但是是令一钟方式。
我们可以用
select namefrom mysql.proc where db=’数据库名’;
或者
selectroutine_name from information_schema.routines whereroutine_schema='数据库名';
或者
show procedurestatus where db='数据库名';
进行查询。
如果我们想知道,某个存储过程的详细,那我们又该怎么做呢?是不是也可以像操作表一样用describe表名进行查看呢?
答案是:我们可以查看存储过程的详细,但是需要用另一种方法:
SHOW CREATEPROCEDURE 数据库.存储过程名;
就可以查看当前存储过程的详细。
MySQL存储过程的基本函数
(1).字符串类
CHARSET(str) //返回字串字符集 CONCAT (string2 [,... ])//连接字串 INSTR (string ,substring )//返回substring首次在string中出现的位置,不存在返回0 LCASE (string2 ) //转换成小写 LEFT (string2 ,length )//从string2中的左边起取length个字符 LENGTH (string )//string长度 LOAD_FILE (file_name )//从文件读取内容 LOCATE (substring , string[,start_position ] ) 同INSTR,但可指定开始位置 LPAD (string2 ,length ,pad )//重复用pad加在string开头,直到字串长度为length LTRIM (string2 ) //去除前端空格 REPEAT (string2 ,count )//重复count次 REPLACE (str ,search_str,replace_str ) //在str中用replace_str替换search_str RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length RTRIM (string2 ) //去除后端空格 STRCMP (string1 ,string2 )//逐字符比较两字串大小, SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符, 注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
数学类
ABS (number2 ) //绝对值 BIN (decimal_number )//十进制转二进制 CEILING (number2 )//向上取整 CONV(number2,from_base,to_base) //进制转换 FLOOR (number2 )//向下取整 FORMAT (number,decimal_places) //保留小数位数 HEX (DecimalNumber )//转十六进制 注:HEX()中可传入字符串,则返回其ASC-11码,如HEX('DEF')返回4142143 也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19 LEAST (number , number2 [,..]) //求最小值 MOD (numerator ,denominator )//求余 POWER (number ,power )//求指数 RAND([seed])//随机数 ROUND (number [,decimals ])//四舍五入,decimals为小数位数]
注:返回类型并非均为整数.
日期时间类
ADDTIME (date2 ,time_interval ) //将time_interval加到date2 CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区 CURRENT_DATE ( ) //当前日期 CURRENT_TIME ( ) //当前时间 CURRENT_TIMESTAMP ( ) //当前时间戳 DATE (datetime ) //返回datetime的日期部分 DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间 DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间 DATEDIFF (date1 ,date2 ) //两个日期差 DAY (date ) //返回日期的天 DAYNAME (date ) //英文星期 DAYOFWEEK (date ) //星期(1-7) ,1为星期天 DAYOFYEAR (date ) //一年中的第几天 EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分 MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串 MAKETIME (hour ,minute ,second ) //生成时间串 MONTHNAME (date ) //英文月份名 NOW ( ) //当前时间 SEC_TO_TIME (seconds ) //秒数转成时间 STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示 TIMEDIFF (datetime1 ,datetime2 ) //两个时间差 TIME_TO_SEC (time ) //时间转秒数] WEEK (date_time [,start_of_week ]) //第几周 YEAR (datetime ) //年份 DAYOFMONTH(datetime) //月的第几天 HOUR(datetime) //小时 LAST_DAY(date) //date的月的最后日期 MICROSECOND(datetime) //微秒 MONTH(datetime) //月 MINUTE(datetime) //分返回符号,正负或0 SQRT(number2) //开平方