MySQL基础19 — 流程控制

概述

本章,您将学习 MySQL 当中的流程控制。流程控制用来实现条件判断和循环逻辑,主要用在 MySQL 的存储过程、存储函数、触发器中。

流程控制主要包括三类:

  1. 分支结构
  2. 循环结构
  3. 跳转控制

分支结构

if 函数

基本语法为:

if(表达式, 值1, 值2)

当表达式为真,则输出 值1,当表达式为假,则输出 值2

一个简单的例子:

select if(50>100,'真','假') as `test`;
+------+
| test |
+------+
| 假   |
+------+
1 row in set (0.00 sec)

在存储函数中的简单使用:

use home;

delimiter //
create function get_salary_grade( salary decimal(10,2) ) returns char(1)
begin
    declare grade char(1) default 'd';

    # if 函数的多层嵌套
    set grade:=if( salary <= 5000, 'd',
    if( salary <= 8000, 'c',
    if( salary <= 10000 , 'b', 'a'))
    );

    return grade;
end //

delimiter ;

select get_salary_grade(6000);
+------------------------+
| get_salary_grade(6000) |
+------------------------+
| c                      |
+------------------------+
1 row in set (0.00 sec)

drop function if exists home.get_salary_grade;

if 结构

该结构只能存在于存储过程或存储函数或触发器的 begin...end 代码块中,不能单独存在,基本语法为:

...
begin
    if 条件1 then 语句1;
    elseif 条件2 then 语句2;
    ...
    [else 语句n];
    end if;
end
...

上面的 if 函数改造为 if 分支结构:

use home;

delimiter //

create function get_salary_grade_if( salary decimal(10,2) ) returns char(1)
begin
    declare grade char(1) default 'd';

    if salary <= 5000 then set grade:='d';
    elseif salary <= 8000 then set grade:='c';
    elseif salary <= 10000 then set grade:='b';
    else set grade:='a';
    end if;

    return grade;
end //

delimier ;

select get_salary_grade_if(15000);
+----------------------------+
| get_salary_grade_if(15000) |
+----------------------------+
| a                          |
+----------------------------+
1 row in set (0.00 sec)

drop function if exists home.get_salary_grade_if;

case 结构

在前面的 《MySQL基础08 --- DQL2》 文章中介绍过 case 的单独用法,当作为 select 的查询列表时,case 有两种语法:

# 第一种
## 当你不键入 else 后面的语法时,没有匹配到的则会以 null 进行显示。
case 表达式或字段或变量 
   when 常量1 then 要显示的值1或者语句1  
   when 常量2 then 要显示的值2或者语句2  
   ...
   else 要显示的值n或者语句n或者字段
end

## 示例如下:
select
   name,
   case Continent
     when 'Asia' then '亚洲'
     when 'north america' then '北美'
     else Continent
   end as `temp`
from
country;

# 第二种
## 当你不键入 else 后面的语法时,没有匹配到的则会以 null 进行显示。
case
   when 条件1 then 要显示的值1或者语句1
   when 条件2 then 要显示的值2或者语句2
   ...
   else  要显示的值n或者语句n
end

## 示例如下:
select
   name,
   case
     when Continent = 'Asia' then '亚洲'
     when Continent in ('north america', 'Africa') then 'A_N'
     else Continent
   end as `temp`
from
country;

小提示
上面的两种语法中, then 关键字后面的 **语句** 必须是 **标量子查询**(结果集只有一行一列的查询)。

case when then 语法也可以用在 begin...end 代码块中,其语法如下:

# 第一种
## 当你不键入 else 后面的语法时,没有匹配到的则会以 null 进行显示。
...
begin
   case 表达式或字段或变量
   when 要判断的值 then 语句1;
   when 要判断的值 then 语句2;
   when 要判断的值 then 语句3;
   when 要判断的值 then 语句4;
   ...
   else  语句n;
   end case;
end
...

# 第二种
## 当你不键入 else 后面的语法时,没有匹配到的则会以 null 进行显示。
...
begin
   case
   when 判断条件1 then 语句1;
   when 判断条件2 then 语句2;
   when 判断条件3 then 语句3;
   ...
   else  语句n;
   end case;
end
...

同样的要求 —— then 关键字后面的 语句 必须是 标量子查询(结果集只有一行一列的查询)。

如下面的例子:

use world;

delimiter //
create procedure demo1( in cname char(52) )
begin
   set @n:=1;
   select gnp into @n from country where name=cname;
   case
     # concat 函数用来拼接字符串
     when @n>=10000 then select concat(name, '+', gnp, '+', code) from country where name=cname;
   else select @n;
   end  case;
end //

delimiter ;

call demo1('china');
+-----------------------------------+
| concat(name, '+', gnp, '+', code) |
+-----------------------------------+
| China+982268.00+CHN               |
+-----------------------------------+
1 row in set (0.04 sec)

drop procedure if exists world.demo1;

循环结构

有三个循环结构:

  • WHILE 循环
  • LOOP 循环
  • REPEAT 循环

WHILE 循环

基本语法为:

[标签名:]while 循环条件 do
  循环体;
end while [标签名];

写一个无参存储过程,求等差数列的前 100 项的和,公差为 1,第一项的值为 1,第 100 项的值为 100。

use world;

delimiter //
create procedure count_sum()
begin
  declare x int default 0;
  declare y int default 1;
    while y<= 100 do
      set x:=x+y;
      set y:=y+1;
    end while;
    select x;
end //

delimiter ;

call count_sum();
+------+
| x    |
+------+
| 5050 |
+------+
1 row in set (0.00 sec)

drop procedure if exists world.count_sum;

LOOP 循环

基本语法为:

[标签名:]loop
  循环体;
end loop [标签名];

写一个无参存储过程,求等比数列前 20 项的和,公比为 2,第一项的值为 1(2的0次方),第 20 项的值为 1048576(2的19次方)

use world;

delimiter //
create procedure geometric_progression()
begin
  declare x int default 0;
  declare y int default 0;
    n:loop
      set x:=x+power(2,y);
      set y:=y+1;
        if y> 20 then leave n;
        end if;
    end loop n;
    select x;
end //

delimiter ;

call geometric_progression();
+---------+
| x       |
+---------+
| 2097151 |
+---------+
1 row in set (0.00 sec)

drop procedure world.geometric_progression;

power(x,y) 函数表示以 x 为底数且以 y 为指数的幂运算,例如 power(2,3) 的输出为 8:

select power(2,3);
+------------+
| power(2,3) |
+------------+
|          8 |
+------------+

需要注意的是,LOOP 循环默认是一个是死循环,因此你需要使用相关的关键字进行跳出,在上面的例子中,使用的是 leave 关键字。

REPEAT 循环

基本语法为:

[标签名称:]repeat
  循环体
until  结束循环的条件
end repeat [标签名称];

写一个有参存储过程,求等差数列的前 n 项的和,公差为 1,第一项的值为 1:

use world;

delimiter //
create procedure sum_repeat(in n int)
begin
    declare x int default 1;
    repeat
      set x:=x+n;
      set n:=n-1;
    until n=1
    end repeat;
    select x; 
end //

delimiter ;

call sum_repeat(50);
+------+
| x    |
+------+
| 1275 |
+------+
1 row in set (0.00 sec)

drop procedure world.sum_repeat;

跳转控制

主要有两个:

  1. leave - 用于退出循环或 begin...end 代码块
  2. iterate - 跳过当次的循环并进入到下一次循环

leave 退出循环的例子在上面的 LOOP 循环中已经演示

再来看一个 iterate 的例子:

use home;

create table p1(
    name varchar(10) not null
);

delimiter //
create procedure insert_odd_num(in y int)
begin
    declare x int default 0;
    a:while x<y do
      set x:=x+1;
      if mod(x,2)=0 then iterate a;
      end if;
      insert into p1 values(concat('jack',x));
    end while a;
end //

delimiter ;

call insert_odd_num(19);

select * from p1;
+--------+
| name   |
+--------+
| jack1  |
| jack3  |
| jack5  |
| jack7  |
| jack9  |
| jack11 |
| jack13 |
| jack15 |
| jack17 |
| jack19 |
+--------+
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇