MySQL存储过程流程控制全解析

在 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,分为两种写法:

  1. 等值匹配:case 变量 when 值
  2. 条件表达式匹配: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 手动退出
相关推荐
Linux界最忧郁之人1 小时前
OpenStack Victoria双节点实战|Packstack一键部署(CentOS‑Stream‑8)+华为云ECS实操
linux·运维·服务器·centos·华为云·openstack
DevNote_1 小时前
1C1G 服务器从零配置实录(附完整命令)
linux·运维·服务器·javascript·adb·ssh·gmssh
拾起零碎1 小时前
U8/触发器,把自定义项写入批次档案
数据库
进击的荆棘1 小时前
Linux系统——进程信号之保存和捕捉信号
linux·运维·服务器·信号处理·信号
Initialize-le1 小时前
PVC 一直 Pending?五步排查存储绑定
云原生·容器·kubernetes
开开心心就好1 小时前
免安装PDF盖章工具,透明度和位置可调
运维·服务器·前端·javascript·pdf·ocr·1024程序员节
whyutianict_vv3 小时前
云计算 HCIE 认证体系解析:HCIA/HCIP/HCIE 三级科目与知识边界
linux·运维·云计算
IT19959 小时前
Fail2Ban 防护 MySQL 实战|登录失败 3 次,IP 封禁 24 小时
数据库·mysql
夕除9 小时前
redis--IO 多路复用(select + poll)
数据库·sql