9.1 创建存储过程和函数
9.1.1 创建存储过程
创建存储过程,需要使用CREATE PROCEDURE语句。
CREATE PROCEDURE
sp_name ( [proc_parameter] )[characteristics ...]
routine_body
9.1.2 创建存储函数
创建存储过程,需要使用CREATE FUNCTION语句。
CREATE FUNCTION
func_name ( [func_parameter] )
RETURNS type [characteristic ...]
routine_body
这里有可能会出现这样的报错
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variabl
注:
"delimiter//"语句的作用是将MySQL的结束符设置为//,因为MySQL默认的结束符为分号";",为了避免与存储过程中SQL语句的结束符相冲突,需要使用DELIMITER改变存储过程的结束符,并以"END//"结束存储过程,存储过程定义完毕之后再使用"delimiter ;"恢复默认结束符。delimiter也可指定其他符号作为结束符。
分割线-------
这时候执行以下代码即可
set global log_bin_trust_function_creators = 1;
然后在创建存储函数,如下
mysql> create function c_sch1()
-> returns int
-> return (select count(*) from sch1);
Query OK, 0 rows affected (0.01 sec)
9.1.3 变量的使用
1.定义变量
DECLARE var_name[,varname]… date_type [DEFAULT value];
2.为变量赋值
SET var_name = expr [, var_name = expr] ...;
9.1.4 定义条件和处理程序
1.定义条件
使用DECLARE语句
如定义ERROR 1148(42000)错误,名称为command_not_allowed。可以用两种不同的方法来定义。
方法一:使用sqlstate_value
declare command_not_allowed condition for sqlstate "42000"
//方法二:使用mysql_error_code
declare command_not_allowed condition for 1148
2.定义处理程序
还是使用declare语法
如:
定义处理程序的几种方法,代码如下
//方法一:捕获sqlstate_value
declare continue handler for sqlstate '42S02' set @info="NO_SUCH_TABLE";
//方法二:捕获mysql_error_code
declare continue handler for 1146 set @info="NO_SUCH_TABLE";
//方法三:先定义条件,然后在调用
declare no_such_table condition for 1146;
declare continue handler for sqlstate '42S02' set @info="NO_SUCH_TABLE";
9.1.5 光标的使用
1.声明光标
DECLARE关键字来声明光标
DECLARE cursor_name CURSOR FOR select_statement
cursor_name声明光标的名字
select_statement是SELECT语句的内容
2.打开光标
OPEN cursor_name
3.使用光标
FETCH cursor_name INTO var_name[,var_name]...{参数名称}
4.关闭光标
close cursor_name
9.1.6流程控制的使用
1.if语句,示例
判断val值是否为空,如果val值为空,就输出字符串'val is Null';否则输出'val is not NULL';if语句都需要使用end if 来结束。
if val is null
then select 'val is null';
else select 'val is not NULL'
end if;
2.case语句
示例:判断val值等于1、等于2,或者两者都不等。
case val
when 1 then select 'val is 1';
when 2 then select 'val is 2';
else select 'val is not 1 or 2';
end case;
3.loop语句用来重复执行某些语句,与if和case语句相比,loop只是创建一个循环操作的过程,并不进行条件判断。loop内的语句一直重复执行直到循环被退出,跳出循环过程中使用leave子句。
示例:
使用LOOP语句进行循环操作,id值小于等于10之前,将重复执行循环过程。
declare id int default 0;
add_loop: LOOP
SET id=id+1;
if id >=10 then leave add_loop;
end if;
end LOOP add_loop;
4.leave语句
leave语句用来退出任何被标注的流程控制构造
示例
使用leave语句退出循环
循环count加一直到50退出循环
add_sum: LOOP
set @count=@count+1;
if @count=50 then leave add_num;
end loop add_num;
5.ITERATE
ITERATE语句将执行顺序转到语句段开头处
ITERATE label
ITERATE只出现在LOOP、REPATH和WHILE语句内。ITERATE的意思为"再次循环",label参数表示循环的标志.ITERATE语句必须跟在循环标志前面。
ITERATE语句示例:
create procedure doiterate()
begin
declare p1 int default 0;
myloop: LOOP
set p1 =p1 + 1;
if p1 < 10 then ITERATE my_loop;
elseif p1 > 20 then leave my_loop;
end if;
select ' p1 is between 10 and 20';
end LOOP myloop;
end
p1的默认值为0,当p1的值小于10时,重复执行p1加1的操作;当p1大于10并且小于20时,打印消息' p1 is between 10 and 20‘;当p1大于20时,退出循环。
6.REPEAT语句
示例:id值小于等于10之前,将重复执行循环过程
reclare id int default 0;
repeat
set id=id +1;
until id >= 10
end repeat;
循环执行id+1操作,当id值小于10时,循环重复执行,大于则退出循环
7.WHILE语句
示例:
i值小于10时,将重复执行循环过程
declare i int default 0;
while i < 10 DO
set i = i +1
end while;
9.2 调用存储过程和函数
9.2.1 调用存储过程
存储过程的调用是通过CALL语句进行调用的。
CALL sp_name([parameter[,...]])
9.2.2 调用存储函数
存储函数的使用方法与MySQL内部函数的使用方法是一样的。
9.3 查看存储过程和函数
9.3.1 SHOW STATUS语句查看存储过程和函数的状态
SHOW STATUS语句可以查看存储过程和函数的状态。
SHOW {PROCEDURE | FUNCTION} STATUS
[LIKE 'pattern']
9.3.2 SHOW CREATE语句查看存储过程和函数的定义
SHOW CREATE语句查看存储过程和函数的状态。
SHOW CREATE {PROCEDURE | FUNCTION} sp_name
9.3.3 从information_schema.Routines表中查看存储过程和函数的信息
MySQL中存储过程和函数的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息。
SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME=' sp_name ' ;
9.4 修改存储过程和函数
使用ALTER语句可以修改存储过程或函数的特性。
ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
9.5 删除存储过程和函数
删除存储过程和函数,可以使用DROP语句。
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
9.6 MySQL 8.0的新特性——全局变量的持久化
在MySQL数据库中,全局变量可以通过SET GLOBAL语句来设置。例如设置服务器语句超时的限制,可以通过设置系统变量max_execution_time来实现:
SET GLOBAL MAX_EXECUTION_TIME=2000;
使用SET GLOBAL语句设置的变量值只会临时生效。数据库重启后,服务器又会从MySQL配置文件中读取变量的默认值。
MySQL 8.0版本新增了SET PERSIST命令。例如设置服务器的最大连接数为1000:
SET PERSIST max_connections = 1000;
9.7 综合案例——创建存储过程和函数
创建存储过程和函数
通过这一章的学习,应该掌握了如何创建存储过程和存储函数,变量的定义、使用,光标的作用和用途,以及MySQL的控制语句。所有的存储过程和存储函数存储在服务器上,只要调用就可以在服务器上执行。
创建一个存储函数用来统计sch1中的记录数,函数名为ciunt_sch()
1.创建函数时报错
mysql> delimiter //
mysql> create function count_sch()
-> returns int
-> return (select count(*) from sch1);
-> //
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
2.解决方法
mysql> set global log_bin_trust_function_creators=1
-> ;
-> //
Query OK, 0 rows affected (0.00 sec)
3.重新创建即可
mysql> create function count_sch()
-> returns int
-> return (select count(*) from sch1);
-> //
Query OK, 0 rows affected (0.01 sec)
4.调用函数
mysql> select count_sch() //
+-------------+
| count_sch() |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
创建一个存储过程,通过调用存储函数的方法获取表sch中的记录数和sch表中id的和。存储过程名称为add_id,同时使用前面创建的存储函数返回表sch中的记录数,计算出表中所有id之和。
mysql> create procedure add_id1(out count int)
-> begin
-> declare itmp int;
-> declare cur_id cursor for select id from sch1;
-> declare exit handler for not found close cur_id;
-> select count_sch() into count;
-> set @sum=0;
-> open cur_id;
-> repeat
-> fetch cur_id into itmp;
-> if itmp<10
-> then set @sum = @sum + itmp;
-> end if;
-> until 0 end repeat;
-> close cur_id;
-> end;
-> //
Query OK, 0 rows affected (0.10 sec)
这个存储过程的代码中使用到了变量的声明、光标、流程控制、在存储过程中调用存储函数等知识点,结果应该是两条记录,id之和为3;
但这里我调用出来的好像只有存储函数的返回结果,代码如下
mysql> call add_id1(@sum)
-> //
Query OK, 0 rows affected (0.00 sec)
mysql> select @sum//
+------+
| @sum |
+------+
| 2 |
+------+
1 row in set (0.00 sec)
常见疑惑及解答
MySQL存储过程和函数有什么区别?
在本质上,他们都是存储程序。函数只能通过return语句返回单个值或者表对象;而存储过程不允许执行return,但是可以通过out参数返回多个值。函数限制比较多,不能用临时表,只能用表变量,还有一些函数不可用,等等;而存储过程的限制就比较少。函数可以嵌入在SQL语句中使用,可以在SELECT语句中作为查询语句的一部分调用;而存储过程一般是作为一个独立的部分来执行的。
存储过程中的代码可以改变么
目前,MySQL还不提供对已存在的存储过程代码的修改,如果必须要修改存储过程,就必须使用DROP语句删除之后,重新编写代码,或者创建一个新的存储过程。
存储过程中可以调用其他存储过程么
存储过程包含用户定义的SQL语句集合,可以使用CALL语句调用其他存储过程,但是不能使用DROP语句删除其他存储过程。
为什么存储过程的参数不要与数据表中的字段名相同?
在定义存储过程参数列表时,应注意把参数名与数据库表中的字段名区别开来,否则将出现无法预期的结果。
存储过程的参数可以使用中文么
一般情况下,可能会出现存储过程中传入中文参数的情况,例如某个存储过程根据用户的名字查找该用户的信息,传入的参数值可能是中文。这时需要在定义存储过程的时候,在后面加上character set gbk,不然调用存储过程使用中文参数会出错,比如定义userInfo存储过程,代码如下:
CREATE PROCEDURE userInfo(IN u_name Varchar(50) character set gbk,out u_age INT)