mysql手册05_存储过程和存储函数


存储过程和存储函数是存储在数据库中的一段SQL语句集合
通过调用存储过程或存储函数,可以简化开发,减少数据在数据库和服务器间的传输。
存储过程和存储函数的区别是:存储函数有返回值

基本语句:

注:在创建存储过程时,为了避免冲突,需要临时修改语句结束符号:
delimiter $

创建存储过程:
delimiter $

create procedure pro_test1() 
begin 
select 'Hello MySQL'; 
end$

delimiter ;

调用存储过程:
call pro_test1();

+-------------+
| Hello MySQL |
+-------------+
| Hello MySQL |
+-------------+

查看存储过程的两种方法:
select name from mysql.proc where db = "demo01"$
show procedure status\G;

查看存储过程的定义/封装语句:
show procedure pro_test1\G;

删除存储过程:
drop procedure pro_test1;

变量:

declare定义变量和set设置变量值:

create procedure pro_test1() 
begin 
declare num int default 10;
set num = num+10;
select concat('num的值为:',num);
end$

调用存储过程:
call pro_test1();
+-------------------------------+
| concat('num的值为:',num)     |
+-------------------------------+
| num的值为:20                 |
+-------------------------------+

select..into..将查询结果赋值给变量:

create procedure pro_test2() 
begin 
declare num int;
select count(*) into num from city;
select concat('city表中的记录数为:',num);
end$

call pro_test2();
+--------------------------------------------+
| concat('city表中的记录数为:',num)         |
+--------------------------------------------+
| city表中的记录数为:4                      |
+--------------------------------------------+

if条件判断:

create procedure pro_test3()
begin 
declare height int default 175;
declare description varchar(50) default '';
if height >=180 then
	set description='高个子';
elseif height >=170 and height<180 then
	set description='中等个子';
else
	set description='小个子';
end if;
select concat('身高:', height,'对应的类型为:',description);
end$

call pro_test3();
+-----------------------------------------------------------------+
| concat('身高:', height,'对应的类型为:',description)           |
+-----------------------------------------------------------------+
| 身高:175对应的类型为:中等个子                                 |
+-----------------------------------------------------------------+

输入参数:
根据传递的身高变量,判定身高类型

create procedure pro_test4(in height int)
begin 
declare description varchar(50) default '';
if height >=180 then
	set description='高个子';
elseif height >=170 and height<180 then
	set description='中等个子';
else
	set description='小个子';
end if;
select concat('身高:', height,'对应的类型为:',description);
end$

call pro_test4(198);
+-----------------------------------------------------------------+
| concat('身高:', height,'对应的类型为:',description)           |
+-----------------------------------------------------------------+
| 身高:198对应的类型为:高个子                                   |
+-----------------------------------------------------------------+

call pro_test4(178);
+-----------------------------------------------------------------+
| concat('身高:', height,'对应的类型为:',description)           |
+-----------------------------------------------------------------+
| 身高:178对应的类型为:中等个子                                 |
+-----------------------------------------------------------------+

call pro_test4(155);
+-----------------------------------------------------------------+
| concat('身高:', height,'对应的类型为:',description)           |
+-----------------------------------------------------------------+
| 身高:155对应的类型为:小个子                                   |
+-----------------------------------------------------------------+

输出参数:
根据传入的身高变量,获取身高类型并返回

create procedure pro_test5(in height int, out description varchar(10))
begin 
if height >=180 then
	set description='高个子';
elseif height >=170 and height<180 then
	set description='中等个子';
else
	set description='小个子';
end if;
end$

call pro_test5(188,@description);
select @description;
+--------------+
| @description |
+--------------+
| 高个子       |
+--------------+
注:@a表示用户会话变量,连接关闭时将释放。@@a表示系统变量。

case结构:
给定月份,计算所在季度

create procedure pro_test6(mon int)
begin
declare result varchar(10);
case
when mon>=1 and mon<=3 then
set result='第一季度';
when mon>=4 and mon<=6 then
set result='第二季度';
when mon>=7 and mon<=9 then
set result='第三季度';
else
set result='第四季度';
end case;
select concat('传递的月份为:', mon ,',计算出的结果为:', result) as content;
end$

call pro_test6(9);
+---------------------------------------------------------------+
| content                                                       |
+---------------------------------------------------------------+
| 传递的月份为:9,计算出的结果为:第三季度                     |
+---------------------------------------------------------------+

while循环:
计算从1加到n

create procedure pro_test7(n int)
begin
	declare total int default 0;
	declare num int default 1;
	while num <= n do
		set total = total + num;
		set num = num +1;
	end while; 
	select total;
end$

call pro_test7(10);
+-------+
| total |
+-------+
|    55 |
+-------+

repeat循环:
计算从1加到n
注意until语句后面没有分号!

create procedure pro_test8(n int)
begin
	declare total int default 0;
	repeat
		set total = total + n;
		set n = n-1;
		until n=0
	end repeat;
	select total;
end$

call pro_test7(10);
+-------+
| total |
+-------+
|    55 |
+-------+

loop循环,leave退出:
计算从1加到n

create procedure pro_test9(n int)
begin
	declare total int default 0;
	c:loop
	set total=total+n;
	set n = n-1;
	if n<=0 then
		leave c;
	end if; 
	end loop c;
	select total;
end$

call pro_test9(10);
+-------+
| total |
+-------+
|    55 |
+-------+

游标:用来存储查询结果集:
一次fetch读取一行数据
若fetch次数超过数据行数,将报错

准备工作:
create table emp(
	id int(11) not null auto_increment,
	name varchar(50) not null comment '姓名',
	age int(11) comment '年龄',
	salary int(11) comment '薪水',
	primary key(id)
)engine=innodb default charset=utf8;

insert into emp(id,name,age,salary) values(null,'金毛狮王',55,3800),(null,'白眉鹰王',60,4000),(null,'青翼蝠王',38,2800),(null,'紫衫龙王',42,1800);

查询emp表的数据并逐行获取进行展示:
create procedure pro_test10()
begin
	declare e_id int(11);
	declare e_name varchar(50);
	declare e_age int(11);
	declare e_salary int(11);
	declare emp_result cursor for select * from emp;
	
	open emp_result;
	
	fetch emp_result into e_id,e_name,e_age,e_salary;
	select concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary);
	
	fetch emp_result into e_id,e_name,e_age,e_salary;
	select concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary);
	
	close emp_result;
end$

call pro_test10();
+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=1, name=金毛狮王, age=55, salary=3800                                |
+-------------------------------------------------------------------------+
1 row in set (0.05 sec)

+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=2, name=白眉鹰王, age=60, salary=4000                                |
+-------------------------------------------------------------------------+
1 row in set (0.05 sec)

循环获取游标数据:
注:退出条件的声明必须紧跟在游标声明之后!

查询emp表的数据并逐行获取进行展示:
create procedure pro_test11()
begin
	declare e_id int(11);
	declare e_name varchar(50);
	declare e_age int(11);
	declare e_salary int(11);
	declare has_data int default 1;
	
	declare emp_result cursor for select * from emp;
	declare exit handler for not found set has_data=0;
	
	open emp_result;
	
	repeat
		fetch emp_result into e_id,e_name,e_age,e_salary;
		select concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary);
		until has_data=0
	end repeat;
	
	close emp_result;
end$

call pro_test11();
+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=1, name=金毛狮王, age=55, salary=3800                                |
+-------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=2, name=白眉鹰王, age=60, salary=4000                                |
+-------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=3, name=青翼蝠王, age=38, salary=2800                                |
+-------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------------------------------------------------------+
| concat('id=',e_id,', name=',e_name,', age=',e_age,', salary=',e_salary) |
+-------------------------------------------------------------------------+
| id=4, name=紫衫龙王, age=42, salary=1800                                |
+-------------------------------------------------------------------------+
1 row in set (0.01 sec)

存储函数:

定义一个存储函数,获取满足条件的总记录数:
create function fun1(countryId int)
returns int
begin
	declare cnum int;
	select count(*) into cnum from city where country_id = countryId;
	return cnum;
end$

调用存储函数:
select fun1(1);
+------+
| $    |
+------+
|    3 |
+------+

删除存储函数:
drop function fun1;

注:若创建存储函数报错:
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)
使用以下命令解决:
set global log_bin_trust_function_creators=1$