Mysql高级三 之 存储过程和函数
1.存储过程和函数
1.1存储过程和函数概述
存储过程和函数是 事先经过编译并存储在数据库中的一段SQL语句的集合.调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务之间的传输,对于提高数据处理的效率是有好处的.
存储过程和函数的区别在于函数必须有返回值而存储过程没有.
函数:是一个返回值的过程
过程:是一个没有返回值的函数
1.2创建存储过程
CREATE PROCEDURE procedure_name([proc_parameeter[...]])
begin
-- SQL语句
end;
示例:
delimiter $
create procedure pro_test()
begin
select 'Hello MySQL';
end$
delimiter;
结果:
delimiter:
该关键字用来声明SQL语句的分隔符,告诉MySQL解释器,该段命令是否已经结束了,Mysql是否可以执行了.
默认情况下,delimiter是分号;。在命令行客户端中,如果有一行命令以分号结束,那么回车后,MySQL将会执行该命令.
1.3调用存储过程
CALL pro_test;
结果:
1.4查看存储过程
-- 查看db_name数据库中的所有存储过程(这个存储在mysql 数据库下的 proc表中 如下tu)
select name form mysql.proc where db='db_name';
-- 查询存储过程的状态信息
show procedure status\G;
-- 查询某个存储过程的定义
show create procedure test.pro_test1;
1.5删除存储过程
DROP PROCEDURE [IF EXISTS] sp_name;
示例:
drop procedure pro_test;
1.6 语法
存储过程是可以编程的,意味着可以使用变量,表达式,控制结构,来完成比较复杂的功能.
1.6.1 变量
-
DECLARE
通过DECLARE可以定义一个局部变量,该变量的作用范围只能在BEGIN…END块中。
DECLARE var_name[,...] type [DEFAULT value]
示例:
delimiter $ create procedure pro_test2() begin declare num int default 5; select num + 10; end$ delimiter ;
查询:
CALL pro_test2;
查看结果:
-
SET
直接赋值使用SET,可以赋常量值或者赋表达式,具体语法如下:
SET var_name = expr[,var_name = expr] ...
示例:
delimiter $ create procedure pro_list() begin declare name varchar(20); set name = 'MySQL'; select name; end$ delimiter;
查看创建的存储过程
CALL pro_list;
结果:
也可以通过select … into 进行赋值
DELIMITER $
CREATE PROCEDURE pro_test3()
BEGIN
DECLARE num INT;
SELECT COUNT(*) INTO num FROM city;
SELECT CONCAT('city表中的记录数为:',num);
END$
DELIMITER ;
查看创建的存储过程
CALL pro_test3();
结果:
1.6.2 if 条件判断
语法结构:
if search_condition then statement_list
[elseif search_condition then statement_list] ...
[else statement_list]
end if;
需求:
根据定义的身高变量,判定当前身高的所属身材类型
180 及以上 -----------→ 身材高挑
170 - 180 -----------→ 标准身材
170 及以下 -----------→ 一般身材
DELIMITER $
CREATE PROCEDURE pro_test4()
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$
DELIMITER ;
查询:
call pro_test4();
结果:
1.6.3 传递参数
create procedure procedure_name([in/out/inout] 参数名 参数类型)
...
IN: 该参数可以作为输入,也就是需要调用方传入值,默认
OUT: 该参数作为输出,也就是该参数可以作为返回值
INOUT:既可以作为输入参数,也可以作为输出参数
IN-输入
需求:
根据定义的身高变量,判定当前身高的所属类型
示例:
DELIMITER $
create procedure pro_test5(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$
DELIMITER ;
查询:
CALL pro_test5(171);
结果:
OUT-输出
需求:
根据传入的身高变量,获取当前身高的所属身材类型
示例:
DELIMITER $
CREATE PROCEDURE pro_test6(IN height INT, OUT description VARCHAR(100))
BEGIN
IF height >= 180 THEN
SET description='身材高挑';
ELSEIF height >= 170 AND height < 180 THEN
SET description='标准身材';
ELSE
SET description='一般身材';
END IF;
END$
DELIMITER ;
查询:
CALL pro_test6(170,@description);
SELECT @description
结果:
科普:
@description : 这种变量要在变名称前面加上“@”符号,叫做用户会话变量,代表整个会话过程他都有作用的,这个类似于全局变量一样.(当前会话有效)
@@global.sort_buffer_size:这种在变量前加上“@@”符号叫做系统变量
1.6.4case结构
-- 方式一:
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list]...
[ELSE statement_list]
END CASE;
-- 方式二:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE;
示例:
给定一个月份,然后计算出所在的季度
DELIMITER $
CREATE PROCEDURE pro_test7(mouth INT)
BEGIN
DECLARE result VARCHAR(10);
CASE
WHEN mouth>=1 AND mouth <= 3 THEN
SET result = '第一季度';
WHEN mouth>=4 AND mouth <= 6 THEN
SET result = '第二季度';
WHEN mouth>=7 AND mouth <= 9 THEN
SET result = '第三季度';
ELSE
SET result = '第四季度';
END CASE;
SELECT CONCAT('传递的月份为:',mouth,';计算出的结果为:',result) AS content;
END$
DELIMITER ;
查询:
CALL pro_test7(1);
结果:
1.6.5 while循环
语法结构:
while search_condition do
statement_list
end while;
需求:
计算从1加到n的值
CREATE PROCEDURE pro_test8(n INT)
BEGIN
DECLARE total INT DEFAULT 0;
DECLARE START INT DEFAULT 0;
WHILE START <= n DO
SET total = total + START;
SET START = START + 1;
END WHILE;
SELECT total;
END$
DELIMITER ;
结果:
1.6.6repeat结构
有条件的循环控制语句,当满足条件的时候退出循环.while是满足条件才执行,repeat是满足条件退出循环.
语法结构:
REPEAT
statement_list
UNTIL search_condition
END REPEAT;
需求:
计算从1加到n的值
示例:
DELIMITER $
CREATE PROCEDURE pro_test9(IN 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$
DELIMITER ;
查询:
CALL pro_test9(3);
结果:
1.6.7 loop语句
LOOP实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用LEAVE语句实现,具体语法如下:
[begin_lable:] LOOP
statement_list
END LOOP [end_label]
如果不存在statement_list中增加退出循环语句,那么LOOP语句可以用来实现简单的死循环.
1.6.8 leave语句
用来从标注的流程构造中退出,通常和BEGIN … END 或者循环一起使用.下面是一个使用LOOP和LEAVE的简单例子,退出循环:
DELIMITER $
create procedure pro_test11(n int)
begin
declare total int default 0;
ins: loop
set total = total + n;
set n = n - 1;
if n <= 0 then
leave ins;
end if;
end loop ins;
select total;
end$
DELIMITER ;
查询:
CALL pro_test11(4);
结果:
1.6.9游标/光标
游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、OPEN、FETCH和CLOSE,其语法如下.
声明光标:
DECLARE cursor_name CURSOR FOR select_statement;
OPEN光标:
OPEN cursor_name;
FETCH光标:
FETCH cursor_name INTO var_name[,var_name] ...
CLOSE光标:
CLOSE cursor_name;
示例:
初始化版本
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表中数据,并逐行获取进行展示 获取两条数据
DELIMITER $
CREATE PROCEDURE pro_test12()
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,', 薪资为:',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,', 薪资为:',e_salary);
CLOSE emp_result;
END$
DELIMITER ;
查询:
call pro_test12();
结果:
-- 获取4条数据
DELIMITER $
CREATE PROCEDURE pro_test13()
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,', 薪资为:',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,', 薪资为:',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,', 薪资为:',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,', 薪资为:',e_salary);
CLOSE emp_result;
END$
DELIMITER ;
通过循环结构获取游标的数据
DELIMITER $
CREATE PROCEDURE pro_test14()
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,', 薪资为:',e_salary);
UNTIL has_data = 0
END REPEAT;
CLOSE emp_result;
END$
DELIMITER ;
查询:
结果:(可以明显看见有1,2,3,4个结果)
1.7存储函数
语法结构:
CREATE FUNCTION function_name([param type ...])
RETURNS type
BEGIN
...
END;
案例:
定义一个存储过程,请求满足条件的记录数;
DELIMITER $
CREATE FUNCTION count_city(countryId int)
returns int
begin
declare cnum int;
select count(*) into cnum from city where country_id = countryId;
return cnum;
end$
DELIMITER ;
查询:
SELECT count_city(1);
结果:
来源:CSDN
作者:奋斗的小菜菜
链接:https://blog.csdn.net/qq_40539437/article/details/104107676