这里使用的是MySQL 8
- 关键字
- 存储过程相关操作
- 声明语句结束符
- 创建存储过程
- 存储过程开始和结束
- 变量的使用
- 变量赋值
- 用户变量
- 局部变量
- 查看变量值
- 调用存储过程
- 删除存储过程
- 查询数据库有哪些存储过程
- 查看存储过程详情
- 存储过程注释
- 存储过程参数类型
- 参数类型:IN
- 参数类型:OUT
- 参数类型:INOUT
- 存储过程控制语句
- 变量的作用域
- 条件语句
- case语句
- while循环语句
- repeat循环语句
- loop循环语句
- LABELS标签
- ITERATE迭代
- 游标遍历查询结果集
这里使用的是MySQL 8)
关键字
括号中是小写,看起来方便,但关键字还是建议写成大写形式的。不过学习时可以先写成小写,毕竟自己看着舒服!
关键字 | 作用 |
| 声明存储过程体语句结束符 |
| 创建存储过程(其实应该分开,两个关键字,但这样记好记),可以传参 |
参数类型: | 表示参数是输入参数(传入值可以是字面量或变量) |
参数类型: | 表示参数是输出参数,向调用者返回数据(可以返回多个值)(传出值只能是变量) |
参数类型: | 表示参数即是输入参数又是输出参数(值只能是变量) |
| 存储过程开始和结束标签 |
| 用在用户变量名前,表示该变量是用户变量 |
| 声明局部变量,只能在 |
| 给变量赋值 |
| 调用存储过程 |
存储过程相关操作
声明语句结束符
语句结束符用在
END
关键字后面,用来表示存储体过程结束。如:END $$
。
- 命令:
DELIMITER 符号(可以自定义)
- 示例
DELIMITER $$
或者
DELIMITER //
- 注意
在存储过程结束后,要将语句结束符修改回;
,即:
DELIMITER ;
创建存储过程
- 命令
CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数数据类型 )
或:
CREATE PROCEDURE 数据库名.存储过程名(IN|OUT|INOUT 参数名 参数数据类型 )
默认情况下,存储过程和默认数据库相关联,如果想指定存储过程创建在某个特定的数据库下,那么在过程名前面加数据库名做前缀。
- 示例
CREATE PROCEDURE myprocedure(IN test_in int)
存储过程开始和结束
- 命令
BEGIN
存储过程体
END $$
- 示例
CREATE PROCEDURE myprocedure(IN test_in int)
BEGIN
存储过程体
END $$
这组关键字还可以嵌套使用、贴标签等,示例:
CREATE PROCEDURE myprocedure(IN test_in int)
label1: BEGIN
label2: BEGIN
存储过程体
END label2 ; -- 注意这里的封号
END label1 $$
变量的使用
变量赋值
- 命令
set 变量名 = 值
用户变量
用户变量可以在存储过程体外声明,使用
@
符号表明该变量是用户变量。
- 形式
@变量名
- 声明并赋值
set @u_variable= 1;
- 注意
@
只是表明变量是用户变量,可以在存储过程体外声明,并不意味着用户变量是用@
来创建,如:@u_variable;
是不正确的。- 声明和使用用户变量时,都需要加上
@
,如:select @u_variable
。- 滥用用户变量会导致程序难以理解及管理。
局部变量
局部变量只能存在与
BEGIN ... END
之内,使用DECLARE
声明
- 命令
DECLARE 变量名 数据类型 [default value]
- 数据类型
MySQL数据类型:int, float, date,varchar(length)等 - 声明示例
BEGIN
DECLARE test_int int unsigned default 1;
DECLARE test_numeric number(8,2) DEFAULT 9.95;
DECLARE test_date date DEFAULT '2020-7-18';
DECLARE test_datetime datetime DEFAULT '2020-7-18 15:55:59';
DECLARE test_varchar varchar(255) DEFAULT 'hello world';
END $$
- unsigned : 无符号
- signed :有符号
- 引用示例
CREATE PROCEFURE myprocedure(OUT t_int int)
BEGIN
DECLARE test_int int unsigned default 1;
set t_int = test_int;
END $$
查看变量值
- 命令
用在BEGIN .. END
内
select 局部变量名;
- 或者:
用在存储过程体外
select @用户变量名;
调用存储过程
- 命令
call 存储过程名
- 示例:@t_int是返回参数
call myprocedure(@t_int);
select @t_int;
删除存储过程
- 命令
DROP PROCEDURE 存储过程名
查询数据库有哪些存储过程
- 命令
show procedure status where db='数据库名';
或者:
select routine_name from information_schema.routines where routine_schema='数据库名';
查看存储过程详情
- 命令
show create procedure 数据库名.存储过程名;
存储过程注释
使用双横杠代表注释。
- 命令
-- 这里是注释内容
存储过程参数类型
- 首先,创建一个数据库,并插入数据
create table t_user(
id int primary key auto_increment,
username varchar(30),
sex varchar(10)
)engine = innodb;
insert into t_user(id, username, sex) values(default, "吕布", "男");
insert into t_user(id, username, sex) values(default, "貂蝉", "女");
以下写的是比较完整的存储过程模板,可以借鉴以下!!!
参数类型:IN
表示参数是输入类型参数,由调用者传递给存储过程(传入值可以是字面量或变量)。下面代码:从用户表中查询用户id为1的用户。
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS test_in;
CREATE PROCEDURE test_in(IN t_id int)
BEGIN
SELECT * FROM t_user WHERE id = t_id;
END $$
DELIMITER ;
set @t_id = 1;
call test_in(@t_id);
参数类型:OUT
表示参数是输出参数,由存储过程返回给调用者,(可以返回多个值,传出值只能是变量)。下面代码:从user表中查出用户id为2的用户的性别。
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS test_out;
CREATE PROCEDURE test_out(OUT t_sex varchar(10))
BEGIN
DECLARE u_sex varchar(10) DEFAULT '男';
set u_sex = (select sex from t_user where id=2);
set t_sex = u_sex;
END $$
DELIMITER ;
call test_out(@t_sex);
select @t_sex;
参数类型:INOUT
表示这个参数即是输入参数又是输出参数,以下代码功能:传递用户名称,获取用户性别。
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS test_inout;
CREATE PROCEDURE test_inout(INOUT t_msg varchar(30))
BEGIN
DECLARE t_msg_tmp varchar(10) DEFAULT '男';
set t_msg_tmp = (select sex from t_user where username=t_msg);
set t_msg = t_msg_tmp;
END $$
DELIMITER ;
set @t_msg = '貂蝉';
call test_inout(@t_msg);
select @t_msg;
存储过程控制语句
变量的作用域
在
BEGIN ... END
内声明的局部变量,在嵌套使用时,外层声明的变量可以在内层进行访问,但是内层的访问在遇到自己的END时,就会消失,无法在外层访问到。可以通过OUT参数等方式保存下来。
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc()
BEGIN
DECLARE x1 int unsigned default 1;
BEGIN
DECLARE x1 int unsigned default 2; -- 内层的x1只在本层有效
select x1;
END; -- 注意这里的封号
select x1; -- 这里是外层的x1,内层的x1已经失效
END $$
DELIMITER ;
call proc();
条件语句
- 命令
if 条件 then
执行语句;
elseif 条件 then
执行语句;
else
执行语句;
end if;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
DECLARE x1 int unsigned default 3;
if x1=1 then
set t_num=1;
elseif x1=2 then
set t_num=2;
else
set t_num=3;
end if;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
case语句
- 命令
case 条件变量
when 条件值 then
执行语句;
when 条件值 then
执行语句;
else
执行语句;
end case;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
DECLARE x1 int unsigned default 3;
case x1
when 1 then
set t_num = 1;
when 2 then
set t_num = 2;
else
set t_num =3;
end case;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
while循环语句
先判断条件是否符合,符合才执行语句。只有符合条件,才执行循环体。也就是
只有符合条件才进行循环
- 命令
while 条件 do
执行语句;
end while;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
while t_num <3 do
set t_num = t_num + 1;
end while;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
repeat循环语句
先执行依次语句,在判断是否符合条件,不符合则继续执行语句。直到符合条件,才不执行循环体,否则一直执行,也就是
直到符合条件才退出循环
。
- 命令
repeat
执行语句
until 循环条件
end repeat;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
repeat
set t_num = t_num + 1;
until t_num >3
end repeat;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
loop循环语句
loop不需要给定循环条件,使用
标签
和leave
关键字退出循环。我们可以使用if
条件语句去控制loop循环次数。
- 命令
自定义标签:loop
执行语句;
leave 自定义标签;
end loop;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
loop_label:loop
set t_num = t_num + 1;
if t_num > 3 then
leave loop_label;
end if;
end loop;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
LABELS标签
标签,也叫标号,可以用在 begin、repeat、while 或者 loop 语句前,语句标号只能在合法的语句前面使用。可以跳出循环,使运行指令达到复合语句的最后一步。不需要加引号,直接写即可!如上
loop_label
所示那样!
ITERATE迭代
ITERATE 通过引用复合语句的标签,来重新开始复合语句。
- 命令
iterate 标签;
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc(INOUT t_num int)
BEGIN
loop_label:loop
set t_num = t_num + 1;
if t_num = 3 then
set t_num = t_num+1;
iterate loop_label;
end if;
if t_num > 6 then
leave loop_label;
end if;
end loop;
END $$
DELIMITER ;
set @t_num = 0;
call proc(@t_num);
select @t_num;
游标遍历查询结果集
当我们需要对查询的结果集循环进行处理时,就可以使用游标来逐一获取结果集中的值,再逐一进行处理即可。
- 命令
-- 定义while循环标志,不同循环语句,判定条件不同,注意了
-- 在MySQL中,int类型0代表false,1代表true,done可以自定义,是比变量名而已
DECLARE done int default true;
-- 定义游标
DECLARE cur CURSOR FOR (具体的查询语句);
-- 设定循环标志为结束标志,当游标中没有数据时,设定标志位为false,结束while循环
DECLARE CONTINUE HANDLER FOR NOT FOUND set done = false;
-- 打开游标
OPEN cur;
-- 使用while循环语句
while done do
-- 使用FETCH关键字从游标中取值,使用INTO关键字将值注入局部变量
FETCH cur INTO 局部变量1, 局部变量2;
-- 具体操作
执行语句;
end while;
-- 关闭游标
CLOSE cur;
- 数据库表
- 代码示例
DELIMITER $$
DROP PROCEDURE IF EXISTS proc;
CREATE PROCEDURE proc()
BEGIN
-- 为数据库表的每个字段设置局部变量,用户保存
DECLARE tmp_id int unsigned default 1;
DECLARE tmp_username varchar(30) default '';
DECLARE tmp_sex varchar(10) default '男';
-- 定义循环标志
DECLARE done int default true;
-- 定义游标
DECLARE cur CURSOR FOR (select * from t_user);
-- 设定循环标志为结束标志
DECLARE CONTINUE HANDLER FOR NOT FOUND set done = false;
-- 打开游标
OPEN cur;
-- 使用while循环语句
while done do
FETCH cur INTO tmp_id, tmp_username, tmp_sex;
-- 具体操作
select tmp_id,tmp_username,tmp_sex;
end while;
-- 关闭游标
CLOSE cur;
END $$
DELIMITER ;
call proc();