在 MySQL 存储过程中,支持流程控制语句,用来实现分支判断、循环逻辑,类似编程语言里的 if、switch、for、while。主要分为:if、case、while、repeat、loop,配合 leave、iterate 实现循环跳出与继续。
1.1 if 判断
IF 用来做多分支条件判断,满足对应条件就执行对应逻辑,支持 if ... elseif ... else ... end if 结构。
注意:MySQL 中
=既可以做比较,也可以赋值;:=专门用来赋值,避免歧义。
语法:
if 条件判断 then
-- 分支操作
elseif 条件判断 then
-- 分支操作
else
-- 分支操作
end if;
例 1:根据年龄判断成年状态
mysql> delimiter $$
mysql> create procedure if_user_age(in age int,out msg varchar(255))
begin
if age <18
then
set msg :='未成年';
elseif age =18
then
set msg :='刚成年';
else
set msg :='已成年';
end if;
end $$
mysql> delimiter ;
mysql> set @msg:="Not Data";
mysql> call if_user_age(16,@msg);
mysql> select @msg;
+--------+
| @msg |
+--------+
| 未成年 |
+--------+
例 2:输入成绩,评定等级 规则:
-
score < 60 :不及格
-
60 ≤ score <80 :及格
-
80 ≤ score <90 :良好
-
90 ≤ score ≤100 :优秀
-
score >100 :成绩错误
mysql> delimiter mysql> create procedure proc11_if(in score int) begin if score < 60 then select '不及格'; elseif score < 80 then select '及格' ; elseif score >= 80 and score < 90 then select '良好'; elseif score >= 90 and score <= 100 then select '优秀'; else select '成绩错误'; end if; end
mysql> delimiter ;mysql> call proc11_if(120);
mysql> call proc11_if(86);
例 3:输入员工姓名,判断薪资档位 沿用 mydb7_openlab 库的 emp_new 表
mysql> use mydb7_openlab;
mysql> select * from emp_new;
+------+------+------+----------------+----------+-------+
| sid | name | age | worktime_start | incoming | dept2 |
+------+------+------+----------------+----------+-------+
| 1789 | 张三 | 35 | 1980-01-01 | 4000 | 101 |
| 1674 | 李四 | 32 | 1983-04-01 | 3500 | 101 |
| 1776 | 王五 | 24 | 1990-07-01 | 2000 | 101 |
| 1568 | 赵六 | 57 | 1970-10-11 | 7500 | 102 |
| 1564 | 荣七 | 64 | 1963-10-11 | 8500 | 102 |
| 1879 | 牛八 | 55 | 1971-10-20 | 7300 | 103 |
+------+------+------+----------------+----------+-------+
mysql> delimiter $$
mysql> create procedure proc12_if(in in_ename varchar(50))
begin
declare result varchar(20);
declare var_sal int;
select incoming into var_sal from emp_new where name = in_ename;
if var_sal < 3000
then
set result = '试用薪资';
elseif var_sal<8000
then
set result = '转正薪资';
else
set result = '元老薪资';
end if;
select result;
end$$
mysql> delimiter ;
mysql> call proc12_if('赵六');
mysql> call proc12_if('荣八');
1.2 case 判断
case 类似其他语言的 switch,分为两种写法:
- 等值匹配:case 变量 when 值
- 条件表达式匹配:case when 条件(适合区间判断)
语法 1(等值匹配):
case 变量
when 值1 then
-- 分支操作1
when 值2 then
-- 分支操作2
else
-- 分支n
end case;
语法 2(条件匹配):
case
when 条件判断1 then
-- 分支操作1
when 条件判断2 then
-- 分支操作2
else
-- 分支n
end case;
例 1:支付方式等值判断
mysql> delimiter $$
mysql> create procedure proc13_case(in pay_type int)
begin
case pay_type
when 1 then select '微信支付' ;
when 2 then select '支付宝支付' ;
when 3 then select '银行卡支付';
else select '其他方式支付';
end case ;
end $$
mysql> delimiter ;
mysql> call proc13_case(2);
mysql> call proc13_case(4);
例 2:case 实现成绩评级(区间判断)
mysql> delimiter $$
mysql> create procedure proc14_case(in score int)
begin
case
when score < 60 then select '不及格';
when score < 80 then select '及格' ;
when score >= 80 and score < 90 then select '良好';
when score >= 90 and score <= 100 then select '优秀';
else select '成绩错误';
end case;
end $$
mysql> delimiter ;
mysql> call proc14_case(88);
mysql> call proc14_case(120);
小结:等值优先用 case;复杂区间、多范围判断优先 if 或者 case 条件写法。
1.3 循环语句
MySQL 存储过程支持三种循环:while、repeat、loop 循环控制关键字:
leave 标签:等价 break,直接跳出结束循环iterate 标签:等价 continue,结束本次循环,直接进入下一轮
while 循环
先判断条件,条件满足才执行循环体(先判断,后执行) 语法:
[标签:]while 循环条件 do
循环体;
end while[标签];
准备测试表:
mysql> select database();
+---------------+
| database() |
+---------------+
| mydb7_openlab |
+---------------+
mysql> create table user (uid int primary key,username varchar(50),password varchar(50));
concat()字符串拼接函数,参数任意一个为 NULL,结果返回 NULL。
示例 1:基础 while 循环批量插入数据
mysql> delimiter $$
mysql> create procedure proc15_while1(in insertcount int)
begin
declare i int default 1;
label:while i<=insertcount do
insert into user(uid,username,password) values(i,concat('user-',i),'123456');
set i=i+1;
end while label;
end $$
mysql> delimiter ;
mysql> call proc15_while1(10);
mysql> select * from user;
+-----+----------+----------+
| uid | username | password |
+-----+----------+----------+
| 1 | user-1 | 123456 |
| 2 | user-2 | 123456 |
| 3 | user-3 | 123456 |
| 4 | user-4 | 123456 |
| 5 | user-5 | 123456 |
| 6 | user-6 | 123456 |
| 7 | user-7 | 123456 |
| 8 | user-8 | 123456 |
| 9 | user-9 | 123456 |
| 10 | user-10 | 123456 |
+-----+----------+----------+
示例 2:while + leave(满足条件跳出循环)
mysql> truncate table user;
mysql> delimiter $$
mysql> create procedure proc16_while2(in insertcount int)
begin
declare i int default 1;
label:while i<=insertcount do
insert into user(uid,username,`password`) values(i,concat('user-',i),'123456');
if i=5
then
leave label;
end if;
set i=i+1;
end while label;
end $$
mysql> delimiter ;
mysql> call proc16_while2(10);
mysql> select * from user;
+-----+----------+----------+
| uid | username | password |
+-----+----------+----------+
| 1 | user-1 | 123456 |
| 2 | user-2 | 123456 |
| 3 | user-3 | 123456 |
| 4 | user-4 | 123456 |
| 5 | user-5 | 123456 |
+-----+----------+----------+
示例 3:while + iterate(跳过本次循环)
mysql> truncate table user;
mysql> delimiter $$
mysql> create procedure proc17_while3(in insertcount int)
begin
declare i int default 1;
label:while i<=insertcount do
set i=i+1;
if i=5
then
iterate label;
end if;
insert into user(uid,username,`password`) values(i,concat('user-',i),'123456');
end while label;
end $$
mysql> delimiter ;
mysql> call proc17_while3(10);
mysql> select * from user;
# 没有uid=5这条记录
+-----+----------+----------+
| uid | username | password |
+-----+----------+----------+
| 2 | user-2 | 123456 |
| 3 | user-3 | 123456 |
| 4 | user-4 | 123456 |
| 6 | user-6 | 123456 |
| 7 | user-7 | 123456 |
| 8 | user-8 | 123456 |
| 9 | user-9 | 123456 |
| 10 | user-10 | 123456 |
| 11 | user-11 | 123456 |
+-----+----------+----------+
repeat 循环
先执行循环体,再判断 until 条件;条件成立,退出循环(先执行,后判断,至少执行一次) 语法:
[标签:]repeat
循环体;
until 条件表达式
end repeat [标签];
示例:
mysql> truncate table user;
mysql> delimiter $$
mysql> create procedure proc18_repeat(in insertCount int)
begin
declare i int default 1;
label:repeat
insert into user(uid, username, password) values(i,concat('user-',i),'123456');
set i = i + 1;
until i > insertCount
end repeat label;
select '循环结束';
end $$
mysql> delimiter ;
mysql> call proc18_repeat(100);
loop 循环
死循环结构,自身不带终止条件,必须手动用 leave 跳出,否则无限循环 语法:
[标签:] loop
循环体;
if 条件表达式
then
leave [标签];
end if;
end loop;
示例:
mysql> truncate table user;
mysql> delimiter $$
mysql> create procedure proc19_loop(in insertCount int)
begin
declare i int default 1;
label:loop
insert into user(uid, username, password) values(i,concat('user-',i),'123456');
set i = i + 1;
if i > 5
then
leave label;
end if;
end loop label;
select '循环结束';
end $$
mysql> delimiter ;
mysql> call proc19_loop(10);
三种循环对比总结
表格
| 循环 | 判断时机 | 特点 |
|---|---|---|
| while | 先判断,后执行 | 条件不满足,一次都不执行 |
| repeat | 先执行,后判断 | 至少执行一次,until 条件成立退出 |
| loop | 无内置判断 | 裸循环,必须配合 leave 手动退出 |