存储过程和函数

作用:直接调用存储函数,使用select 存储函数名称,就会执行一系列的名称。。

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)
posted @ 2021-09-22 13:49  索匣  阅读(237)  评论(0编辑  收藏  举报