MySQL:进阶巩固-存储过程
目录
- 一、存储过程的概述
- 二、存储过程的基本使用
- 2.1 创建存储过程
- 2.2 使用存储过程
- 2.3 查询指定数据库的存储过程以及状态信息
- 2.4 查看某个存储过程的定义
- 2.5 删除存储过程
- 2.6 案例
- 三、存储过程的变量设置
- 3.1 系统变量
- 3.2 用户自定义变量
- 3.3 局部变量
- 四、IF判断
- 五、参数
- 六、CASE判断
- 七、While循环
- 八、repeat循环
- 九、loop循环
- 十、游标
- 十一、条件处理程序
一、存储过程的概述
存储过程是
事先经过编译并存储在数据库中的一段SQL语句的集合
,调用存储过程可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。
存储过程思想上很简单,就是数据库SQL语言层面的代码封装与重用
。
特点:
- 封装、复用
- 可以接收参数,也可以返回数据
- 减少网络交互,提高效率
二、存储过程的基本使用
2.1 创建存储过程
CREATE PROCEDURE 存储过程名称([参数列表])
BEGIN
-- SQL语句
END;
2.2 使用存储过程
CALL 存储过程名称([参数]);
2.3 查询指定数据库的存储过程以及状态信息
SELECT * FROM information_schema.routines WHERE routine_schema=数据库名称;
2.4 查看某个存储过程的定义
SHOW CREATE PROCEDURE 存储过程名称;
2.5 删除存储过程
DROP PROCEDURE IF EXISTS 存储过程名称;
2.6 案例
-- 创建存储过程
CREATE PROCEDURE p1()
BEGIN
SELECT COUNT(*) 人员数量 FROM tb_emp;
END;
-- 调用存储过程
CALL p1();
-- 查询指令数据库的存储过程以及状态信息
SELECT * FROM information_schema.routines WHERE routine_schema='mysql_demo';
-- 查看某个存储过程的定义
SHOW CREATE PROCEDURE p1;
-- 删除存储过程
DROP PROCEDURE IF EXISTS p1;
注意:在命令行中,执行创建存储过程的SQL时,需要通过关键字delimiter指定SQL语句的结束符。
delimiter $$
指定delimiter之后,SQL语句的结束符就是$$,之后还需要在更改回来
delimiter ;
三、存储过程的变量设置
3.1 系统变量
系统变量
是MySQL服务器提供的,不是用户定义的,属于服务器层面。分为全局变量(GLOBAL)
、会话变量(SESSION)
。
查看所有系统变量
SHOW [SESSION|GLOBAL] VARIABLES;
LIKE模糊匹配查找变量
SHOW [SESSION|GLOBAL] VARIABLES LIKE '......';
查看指定变量的值
SELECT @@[SESSION|GLOBAL].系统变量名;
设置系统变量
SET [SESSION|GLOBAL] 系统变量名=值;
SET @@[SESSION|GLOBAL] 系统变量名=值;
注意:
1. 如果没有指定SESSION|GLOBAL,默认是SESSION,绘画变量。
2. MySQL服务重新启动之后,所设置的全局参数会失效,要想不失效,可以在/etc/my.cnf中配置
3.2 用户自定义变量
用户自定义变量
是用户根据需要自己定义的变量,用户变量不用提前声明,在用的时候直接用"@变量名"使用即可。其作用域是当前会话(SESSION)。
赋值
SET @var_name = expr;
SET @var_name := expr; // 推荐使用
SELECT @var_name := expr;
SELECT 字段名 INTO @var_name FROM 表名;
使用
SELECT @var_name;
SET @myname = '张三';
SET @myage = '18';
SET @mygender = '男';
SET @myhobby = '篮球';
SELECT @myname,@myage,@mygender,@myhobby;
注意:如果查询没有定义的变量,他不会报错,只不过获取到的值为NULL
3.3 局部变量
局部变量
是根据需要定义在局部生成的变量,访问之前,需要DECLARE声明。可用作存储过程内的局部变量和输入参数,局部变量的作用范围是在其声明的BEGIN…END快之间。
声明
DECLARE 变量名 变量类型[DEFAULT...];
变量类型就是数据库字段类型:INT、BEGIN、CHAR、VARCHAR、DATE、TIME等
赋值
SET 变量名 = 值;
SET 变量名 := 值;
SELECT 字段名 INTO 变量名 FROM 表名...;
CREATE PROCEDURE p2()
BEGIN
DECLARE stu_count int DEFAULT 0;
SELECT COUNT(*) INTO stu_count FROM tb_user;
SELECT stu_count;
END;
CALL p2();
查询
SELECT 局部变量名;
四、IF判断
IF 条件 THEN
...
ELSEIF 条件2 THEN
...
ELSE
...
END IF;
CREATE PROCEDURE p3()
BEGIN
DECLARE age int DEFAULT 18;
DECLARE result VARCHAR(10);
IF age < 18 THEN
SET result := '小孩';
ELSEIF age >=18 AND age <= 35 THEN
SET result := '青年';
ELSE
SET result := '老年';
END IF;
SELECT result;
END;
CALL p3();
五、参数
类型 | 含义 | 备注 |
---|---|---|
IN | 输入参数 | 默认 |
OUT | 输出参数 | |
INOUT | 输入、输出参数 |
语法
CREATE PROCEDURE 存储过程名称([IN/OUT/INOUT 参数名 参数类型])
BEGIN
....
END;
输入参数与输出参数
CREATE PROCEDURE P4(IN age INT, OUT result VARCHAR(10))
BEGIN
IF age < 18 THEN
SET result := '小孩';
ELSEIF age >=18 AND age <= 35 THEN
SET result := '青年';
ELSE
SET result := '老年';
END IF;
END;
-- 执行存储过程
CALL p4(18, @result);
-- 查看返回结果
SELECT @result;
输入、输出参数
CREATE PROCEDURE p5(INOUT score DOUBLE)
BEGIN
SET score := score * 0.5;
END;
SET @score = 80;
CALL p5(@score);
SELECT @score;
六、CASE判断
语法一:
CASE case_value
WHEN when_value1 THEN statement_list1
WHEN when_value2 THEN statement_list2
...
ELSE statement_list
END CASE;
语法二:
CASE
WHEN search_condition1 THEN statement_list1
WHEN search_condition2 THEN statement_list2
...
ELSE statement_list
END CASE;
-- 根据传入的月份,判断月份所属的季节
-- 1-3月份 第一季度
-- 4-6月份 第二季度
-- 7-9月份 第三季度
-- 10-12月份 第四季度
CREATE PROCEDURE p6(IN month INT, OUT result VARCHAR(10))
BEGIN
CASE
WHEN month >= 1 AND month <=3 THEN
SET result := '第一季度';
WHEN month >= 4 AND month <=6 THEN
SET result := '第二季度';
WHEN month >= 7 AND month <=9 THEN
SET result := '第三季度';
WHEN month >= 10 AND month <=12 THEN
SET result := '第三季度';
ELSE
SET result := '你家有这个月份啊!';
END CASE;
END;
SET @month := 6;
CALL p6(@month, @result);
SELECT CONCAT('您输入的月份为:', @month, ' 所属季度为:', @result)
七、While循环
while循环是有条件的循环控制语句。
满足条件后,再执行循环体中的SQL语句
。
# 先判断条件,如果条件为True,则执行逻辑,否则不执行逻辑
WHILE 条件 DO
SQL逻辑
END WHILE;
-- 计算从1累加到N的值
CREATE PROCEDURE p3(IN n INT, OUT total INT)
BEGIN
DECLARE result int DEFAULT 0;
WHILE n > 0 DO
SET result := result + n;
SET n := n - 1;
END WHILE;
SET total := result;
END;
SET @n := 10;
CALL p3(@n, @total);
SELECT @total;
注意:WHILE中使用OUT变量输出为NULL,如果想要输出,可以先定义一个局部变量最后计算完成之后在设置输出变量。
八、repeat循环
repeat循环是有条件的循环控制语句。
满足条件后,退出循环
。
# 先执行一次逻辑,然后判断逻辑是否满足,如果满足则退出,如果不满足,则继续下一个循环。
REPEAT
SQL逻辑
UNTIL 条件
END REPEAT;
-- 计算从1累加到N的值
CREATE PROCEDURE p4(IN n INT, OUT total INT)
BEGIN
DECLARE result int DEFAULT 0;
REPEAT
SET result := result + n;
SET n := n - 1;
UNTIL n <= 0 END REPEAT;
SET total := result;
END;
SET @n := 10;
CALL p4(@n, @total);
SELECT @total;
九、loop循环
LOOP实现简单的循环,如果不在SQL逻辑中增加退出循环的条件,可以用来实现简单的死循环。
LOOP可以配合两个语句一起使用:
- LEAVE: 配合循环使用,退出循环
- ITERATE:必须用在循环中,跳过本次循环执行下一次循环
[begin_label] LOOP
SQL逻辑
END LOOP [end_label];
LEAVE label; -- 退出循环
ITERATE label; -- 退出本次循环执行下一次循环
CREATE PROCEDURE p5(IN n INT, OUT total INT)
BEGIN
DECLARE result int DEFAULT 0;
sum:LOOP
IF n <= 0 THEN LEAVE sum; END IF;
SET result := result + n;
SET n := n - 1;
END LOOP sum;
SET total := result;
END;
SET @n := 10;
CALL p5(@n, @total);
SELECT @total;
CREATE PROCEDURE p6(IN n INT, OUT total INT)
BEGIN
DECLARE result int DEFAULT 0;
sum:LOOP
IF n <= 0 THEN LEAVE sum; END IF;
IF n%2 = 1 THEN
SET n := n - 1;
ITERATE sum;
END IF;
SET result := result + n;
SET n := n - 1;
END LOOP sum;
SET total := result;
END;
SET @n := 10;
CALL p6(@n, @total);
SELECT @total;
十、游标
游标(CURSOR)
用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环处理。游标的使用包括游标的声明、OPEN(打开)、FETCH(获取)和关闭(CLOSE)。
声明游标
DECLARE 游标名称 CURSOR FOR 查询语句;
打开游标
OPEN 游标名称;
获取游标记录
FETCH 游标名称 INTO 变量;
关闭游标
CLOSE 游标名称;
-- 根据年龄查询用户数据,并将用户名跟专业插入到新表中
CREATE PROCEDURE p1(IN uage INT)
BEGIN
-- 注意:变量一定要声明在游标之前
DECLARE uname VARCHAR(50);
DECLARE uprof VARCHAR(50);
DECLARE u_cursor CURSOR FOR SELECT name,profession FROM tb_user WHERE age <= uage;
DROP TABLE IF EXISTS tb_user_pro;
CREATE TABLE IF NOT EXISTS tb_user_pro(
id int PRIMARY KEY auto_increment,
name VARCHAR(50) COMMENT '姓名',
profession VARCHAR(50) COMMENT '专业'
);
OPEN u_cursor;
WHILE TRUE DO
FETCH u_cursor INTO uname,uprof;
INSERT tb_user_pro(name, profession) VALUES(uname,uprof);
END WHILE;
CLOSE u_cursor;
END;
CALL p1(35);
十一、条件处理程序
条件处理程序(Handler)
可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。
DECLARE handler_action HANDLER FRO condition_value [, condition_value] ... statement;
handler_action
CONTINUE: 继续执行当前程序
EXIT: 终止执行当前程序
condition_value
SQLSTATE sqlstate_value: 状态码,如 02000
SQLWARNING: 所有以01开头的SQLSTATE代码的简写
NOT FOUND: 所有以02开头的SQLSTATE代码的简写
SQLEXCEPTION: 所有没有被SQLWARNING 或 NOT FOUND 捕获的SQLSTATE代码的简写
-- 根据年龄查询用户数据,并将用户名跟专业插入到新表中
CREATE PROCEDURE p2(IN uage INT)
BEGIN
DECLARE uname VARCHAR(50);
DECLARE uprof VARCHAR(50);
DECLARE u_cursor CURSOR FOR SELECT name,profession FROM tb_user WHERE age <= uage;
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE u_cursor;
DROP TABLE IF EXISTS tb_user_pro;
CREATE TABLE IF NOT EXISTS tb_user_pro(
id int PRIMARY KEY auto_increment,
name VARCHAR(50) COMMENT '姓名',
profession VARCHAR(50) COMMENT '专业'
);
OPEN u_cursor;
WHILE TRUE DO
FETCH u_cursor INTO uname,uprof;
INSERT tb_user_pro(name, profession) VALUES(uname,uprof);
END WHILE;
CLOSE u_cursor;
END;
CALL p2(35);