MySQL流程控制(二十八)

二八佳人体似酥,腰悬利剑斩愚夫,虽然不见人头落,暗里教君骨髓枯。

上一章简单介绍了MySQL变量(二十七) ,如果没有看过,请观看上一章

一. 定义条件与处理程序

定义条件是事先定义程序执行过程中可能遇到的问题,处理程序定义了在遇到问题时应当采取的处理方式,并且保证存储过程或函数在遇到警告或错误时能继续执行。这样可以增强存储程序处理问题的能力,避免程序异常停止运行。

说明:定义条件和处理程序在存储过程、存储函数中都是支持的。

一.一 存储过程报错便退出

创建一个存储过程,刚开始报错 user 表里面没有 email 字段

DELIMITER //CREATE PROCEDURE UpdateDataNoCondition()BEGINSET @x = 1;UPDATE user SET email = NULL WHERE id = '1';SET @x = 2;UPDATE user SET name = 'yjl' WHERE id = '1';SET @x = 3;END //DELIMITER ;

调用存储过程:

--  1054 Unknown column 'email' in 'field list' 
call UpdateDataNoCondition();-- 为1 
select @x;

可以看到,此时@x变量的值为1。结合创建存储过程的SQL语句代码可以得出:在存储过程中未定义条件和处理程序,

且当存储过程中执行的SQL语句报错时,MySQL数据库会抛出错误,并退出当前SQL逻辑,不再向下继续执行。

一.二 定义条件

定义条件就是给MySQL中的错误码命名,这有助于存储的程序代码更清晰。它将一个错误名字指定的错误条件关联起来。这个名字可以随后被用在定义处理程序的DECLARE HANDLER语句中。

定义条件使用DECLARE语句,语法格式如下:

DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)

错误码的说明:

  • MySQL_error_codesqlstate_value都可以表示MySQL的错误。
    • MySQL_error_code是数值类型错误代码。
    • sqlstate_value是长度为5的字符串类型错误代码。
  • 例如,在ERROR 1418 (HY000)中,1418是MySQL_error_code,'HY000’是sqlstate_value。
  • 例如,在ERROR 1142(42000)中,1142是MySQL_error_code,'42000’是sqlstate_value。

**举例1:**定义“Field_Not_Be_NULL”错误名与MySQL中违反非空约束的错误类型是“ERROR 1048 (23000)”对应。

#使用MySQL_error_code
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;#使用sqlstate_value
DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';

**举例2:**定义"ERROR 1148(42000)"错误,名称为command_not_allowed。

#使用MySQL_error_code
DECLARE command_not_allowed CONDITION FOR 1148;#使用sqlstate_value
DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';

一.三 定义处理程序

可以为SQL执行过程中发生的某种类型的错误定义特殊的处理程序。定义处理程序时,使用DECLARE语句的语法如下:

DECLARE 处理方式 HANDLER FOR 错误类型 处理语句

  • 处理方式:处理方式有3个取值:CONTINUE、EXIT、UNDO。
    • CONTINUE:表示遇到错误不处理,继续执行。
    • EXIT:表示遇到错误马上退出。
    • UNDO:表示遇到错误后撤回之前的操作。MySQL中暂时不支持这样的操作。
  • 错误类型(即条件)可以有如下取值:
    • SQLSTATE '字符串错误码':表示长度为5的sqlstate_value类型的错误代码;
    • MySQL_error_code:匹配数值类型错误代码;
    • 错误名称:表示DECLARE … CONDITION定义的错误条件名称。
    • SQLWARNING:匹配所有以01开头的SQLSTATE错误代码;
    • NOT FOUND:匹配所有以02开头的SQLSTATE错误代码;
    • SQLEXCEPTION:匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码;
  • 处理语句:如果出现上述条件之一,则采用对应的处理方式,并执行指定的处理语句。语句可以是像“SET 变量 = 值”这样的简单语句,也可以是使用BEGIN ... END编写的复合语句。

定义处理程序的几种方式,代码如下:

#方法1:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info = 'NO_SUCH_TABLE';#方法2:捕获mysql_error_value
DECLARE CONTINUE HANDLER FOR 1146 SET @info = 'NO_SUCH_TABLE';#方法3:先定义条件,再调用
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info = 'NO_SUCH_TABLE';#方法4:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info = 'ERROR';#方法5:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info = 'NO_SUCH_TABLE';#方法6:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = 'ERROR';

一.四 定义条件和定义程序整合

一.四.一 对错误码进行处理程序

在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到MySQL_error_code值为1048时,执行CONTINUE操作,并且将@proc_value的值设置为-1。

DELIMITER //CREATE PROCEDURE UpdateDataNoCondition2()BEGIN#定义处理程序DECLARE CONTINUE HANDLER FOR 1054 SET @proc_value = -1;SET @x = 1;UPDATE user SET email = NULL WHERE id = '1';SET @x = 2;UPDATE user SET name = 'yjl' WHERE id = '1';SET @x = 3;END //DELIMITER ;

进行调用存储过程:

--  变  OK 了, 之前错误码是 1054
call UpdateDataNoCondition2();-- 3   -1 
select @x,@proc_value;

一.四.二 对异常值进行处理信息

给用户表 user 添加 name 的唯一约束

ALTER TABLE user ADD CONSTRAINT uk_user_1 UNIQUE(name);

插入一条数据, 执行两次时,第二次就会报错, key 为 1062

insert into user(name,sex,age) values('岳泽霖','男',18);

image-20230807174723162

定义存储过程,创建是成功的

DELIMITER //CREATE PROCEDURE UpdateDataNoCondition3()BEGIN#定义处理程序DECLARE duplicate_entry CONDITION FOR SQLSTATE '23000' ;DECLARE EXIT HANDLER FOR duplicate_entry SET @proc_value = -1;SET @x = 1;insert into user(name,sex,age) values('abc','男',18);SET @x = 2;-- 第二回肯定报错的insert into user(name,sex,age) values('abc','男',18);SET @x = 3;END //DELIMITER ;

调用并查询:

--  变  OK 了, 之前错误码是 1062 对应的是 23000
call UpdateDataNoCondition3();-- 2   -1 
select @x,@proc_value;

二. 流程控制

解决复杂问题不可能通过一个 SQL 语句完成,我们需要执行多个 SQL 操作。流程控制语句的作用就是控制存储过程中 SQL 语句的执行顺序,是我们完成复杂操作必不可少的一部分。只要是执行的程序,流程就分为三大类:

  • 顺序结构:程序从上往下依次执行
  • 分支结构:程序按条件进行选择执行,从两条或多条路径中选择一条执行
  • 循环结构:程序满足一定条件下,重复执行一组语句

针对于MySQL 的流程控制语句主要有 3 类。注意:只能用于存储程序。

  • 条件判断语句:IF 语句和 CASE 语句
  • 循环语句:LOOP、WHILE 和 REPEAT 语句
  • 跳转语句:ITERATE 和 LEAVE 语句

一直定义这三条数据进行演示和处理, 每一次语句之前都进行重置。

image-20230807175554133

二.一 分支结构 IF

IF 语句的语法结构是:

IF 表达式1 THEN 操作1
[ELSEIF 表达式2 THEN 操作2]……
[ELSE 操作N]
END IF

根据表达式的结果为TRUE或FALSE执行相应的语句。这里“[]”中的内容是可选的。

  • 特点:① 不同的表达式对应不同的操作 ② 使用在begin end中

年龄小于18时,修改姓名:

DELIMITER //
CREATEPROCEDURE `demo`.`p1`(IN `s_id` INT)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;select age into s_age from user where id = s_id;if s_age < 18 thenupdate user set name ='未成年' where id = s_id ;end if ;END //
DELIMITER ;

image-20230807183248952

年龄小于18为未成年, 其余为成年

DELIMITER //
CREATEPROCEDURE `demo`.`p2`(IN `s_id` INT)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;select age into s_age from user where id = s_id;if s_age < 18 thenupdate user set name ='未成年' where id = s_id ;else update user set name ='成年' where id = s_id ;end if ;END //
DELIMITER ;

image-20230807183420277

小于 18 为未成年, 为 18时为刚成年, 大于 18为成年

DELIMITER //
CREATEPROCEDURE `demo`.`p3`(IN `s_id` INT)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;select age into s_age from user where id = s_id;if s_age < 18 thenupdate user set name ='未成年' where id = s_id ;elseif s_age = 18 then update user set name ='刚成年' where id = s_id ;else update user set name ='成年' where id = s_id ;end if ;END //
DELIMITER ;

image-20230807183617412

二.二 分支结构 CASE

CASE 语句的语法结构1:

#情况一:类似于switch
CASE 表达式
WHEN1 THEN 结果1或语句1(如果是语句,需要加分号) 
WHEN2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

CASE 语句的语法结构2:

#情况二:类似于多重if
CASE 
WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加分号) 
WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

case when 形式:

DELIMITER //
CREATEPROCEDURE `demo`.`p4`(IN `s_id` INT)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;select age into s_age from user where id = s_id;case when s_age < 18 thenupdate user set name ='未成年' where id = s_id ;when s_age = 18 then update user set name ='刚成年' where id = s_id ;else  update user set name ='成年' where id = s_id ;end case ;END //
DELIMITER ;

image-20230807184211959

case 表达式 形式:

DELIMITER //
CREATEPROCEDURE `demo`.`p5`(IN `s_id` INT)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;select age into s_age from user where id = s_id;case s_agewhen  16 thenupdate user set name ='16 未成年' where id = s_id ;when 18 then update user set name ='18 刚成年' where id = s_id ;else  update user set name ='成年' where id = s_id ;end case ;END //
DELIMITER ;

image-20230807184416128

二.三 循环 LOOP

LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子句),跳出循环过程。

LOOP语句的基本格式如下:

[loop_label:] LOOP循环执行的语句
END LOOP [loop_label]

其中,loop_label表示LOOP语句的标注名称,该参数可以省略。

查询最小的年龄 循环相加 10 次之后的值

DELIMITER //
CREATEPROCEDURE `demo`.`p7`(OUT sum_age int)-- 存储过程体BEGIN-- 查询年龄declare s_age int;declare num1 int default 0;set s_age = 0;set sum_age = 0;select min(age) into s_age from user ;add_loop: LOOPset num1 = num1 +1;if num1 > 10 then leave add_loop;else set sum_age = sum_age + s_age;end if;end LOOP add_loop;END //
DELIMITER ;

调用:


set @sum_age = 0;
call p7(@sum_age);--  160 
select @sum_age;

二.四 循环结构 WHILE

WHILE语句创建一个带条件判断的循环过程。WHILE在执行语句执行时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环。WHILE语句的基本格式如下:

[while_label:] WHILE 循环条件  DO循环体
END WHILE [while_label];

while_label为WHILE语句的标注名称;如果循环条件结果为真,WHILE语句内的语句或语句群被执行,直至循环条件为假,退出循环。

DELIMITER //
CREATEPROCEDURE `demo`.`p8`(OUT sum_age int)-- 存储过程体BEGIN-- 查询年龄declare s_age int;declare num1 int default 0;set s_age = 0;set sum_age = 0;select min(age) into s_age from user ;-- 循环处理while  num1 < 10 DOset sum_age = sum_age + s_age;set num1 = num1 +1;end WHILE;END //
DELIMITER ;

调用:

set @sum_age = 0;
call p8(@sum_age);--  160 
select @sum_age;

二.五 循环结构 REPEAT

REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT 循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,

如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止。

REPEAT语句的基本格式如下:

[repeat_label:] REPEAT循环体的语句
UNTIL 结束循环的条件表达式
END REPEAT [repeat_label]

repeat_label为REPEAT语句的标注名称,该参数可以省略;REPEAT语句内的语句或语句群被重复,直至expr_condition为真。

DELIMITER //
CREATEPROCEDURE `demo`.`p9`(OUT sum_age int)-- 存储过程体BEGIN-- 查询年龄declare s_age int;declare num1 int default 0;set s_age = 0;set sum_age = 0;select min(age) into s_age from user ;-- 循环处理 REPEAT set sum_age = sum_age + s_age;set num1 = num1 +1;until  num1 >= 10end REPEAT;END //
DELIMITER ;

调用:

set @sum_age = 0;
call p9(@sum_age);--  160 
select @sum_age;

对比三种循环结构:

1、这三种循环都可以省略名称,但如果循环中添加了循环控制语句(LEAVE或ITERATE)则必须添加名称。
2、
LOOP:一般用于实现简单的"死"循环
WHILE:先判断后执行
REPEAT:先执行后判断,无条件至少执行一次

二.六 跳转语句 LEAVE

LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。

如果你有面向过程的编程语言的使用经验,你可以把 LEAVE 理解为 break。

基本格式如下:

LEAVE 标记名

其中,label参数表示循环的标志。LEAVE和BEGIN … END或循环一起被使用。

统计执行的次数, num1 最多执行10次就退出

DELIMITER //
CREATEPROCEDURE `demo`.`p10`(OUT sum_age int ,OUT num1 int)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;set sum_age = 0;set num1 = 0;select min(age) into s_age from user ;-- 循环处理A: while  num1 < 10 DOif s_age < 20 then set num1 = num1 +1;LEAVE A;else set sum_age = sum_age + s_age;set num1 = num1 +1;end if;end WHILE;END //
DELIMITER ;

调用:


set @sum_age = 0;
set @num1 = 0;
call p10(@sum_age,@num1);--  0   1 
select @sum_age, @num1;

二.七 跳转语句 ITERATE

ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处。如果你有面向过程的编程语言的使用经验,你可以把 ITERATE 理解为 continue,意思为“再次循环”。

语句基本格式如下:

ITERATE label

label参数表示循环的标志。ITERATE语句必须跟在循环标志前面。

DELIMITER //
CREATEPROCEDURE `demo`.`p11`(OUT sum_age int ,OUT num1 int)-- 存储过程体BEGIN-- 查询年龄declare s_age int;set s_age = 0;set sum_age = 0;set num1 = 0;select min(age) into s_age from user ;-- 循环处理A: while  num1 < 10 DOif s_age < 20 then set num1 = num1 +1;iterate A;else set sum_age = sum_age + s_age;set num1 = num1 +1;end if;end WHILE;END //
DELIMITER ;

调用:


set @sum_age = 0;
set @num1 = 0;
call p11(@sum_age,@num1);--  0   10
select @sum_age, @num1;


谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/27433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广州VR制作 | 利用VR元宇宙平台开展林地管理培训的优势

在林业领域&#xff0c;实地调查是获取准确数据和深入了解森林生态的重要手段。然而&#xff0c;传统的实地调查方法存在诸多问题&#xff0c;如时间成本高、人力物力投入大、安全风险高等。为了解决这些教学痛点&#xff0c;我们引入了虚拟现实(VR)技术&#xff0c;通过虚拟林…

低代码平台:初创公司的理想选择

对于初创公司而言&#xff0c;时间和资源是宝贵的。他们需要快速构建和部署应用程序&#xff0c;以满足业务需求&#xff0c;提高效率&#xff0c;并保持竞争优势。在这个背景下&#xff0c;低代码平台成为了初创公司的一个理想选择。而Zoho Creator作为一款出色的低代码平台&a…

Linux ARM64架构 动态替换 altinstructions

文章目录 简介一、altinstructions节1.1 .altinstructions1.2 .rela.altinstructions 二、内核模块重定位源码分析参考资料 简介 在内核开发中&#xff0c;有时需要对内核代码进行修补&#xff0c;以解决bug、优化性能或引入新功能。替代指令&#xff08;altinstructions&…

Connection reset原因分析及解决思路

Connection reset原因分析及解决思路 我们在开发过程中经常会出现Connection reset问题&#xff0c;包括http调用&#xff0c;数据库连接等场景。出现Connection reset的原因很多&#xff0c;本文从tcp层面简单介绍下Connection reset出现的原因和问题&#xff0c;以及在实际开…

宏观上看Spring创建对象的过程

宏观上看Spring创建对象的过程 对于对象而言&#xff0c;可以分为简单对象和复杂对象&#xff1b; 简单对象 简单对象指可以直接new的对象&#xff1b; Spring在创建这些对象时&#xff0c;是基于反射来完成的。复杂对象 复杂对象指不能直接new的对象。 比如&#xff1a;要得到…

运行 Jmeter 文件生成 HTML 测试报告,我选择 ANT 工具

概述 ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具&#xff0c;大多用于 Java 环境中的软件开发。 在与 Jmeter 生成的 jmx 文件配合使用中&#xff0c;ant 会完成jmx计划的执行和生成jtl文件&#xff0c;并将jtl文件转化为html页面进行查看。 还可…

Django架构图

1. Django 简介 基本介绍 Django 是一个由 Python 编写的一个开放源代码的 Web 应用框架 使用 Django&#xff0c;只要很少的代码&#xff0c;Python 的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容&#xff0c;并进一步开发出全功能的 Web 服务 Django 本身…

【车道线】TwinLiteNet 复现过程全纪录

码字不易&#xff0c;喜欢的请点赞收藏&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 论文全文翻译&#xff1a;【freespace】TwinLiteNet: An Efficient and Lightweight Model for Driveable Area and Lane Segmentation_莫克_Cheney的博客-CSDN博客 目录…

安装Jenkins

一、什么是Jenkins Jenkins是一个开源软件项目&#xff0c;是基于Java开发的。我们可以利用Jenkins来实现持续集成的功能。 因为Jenkins是基于Java开发的&#xff0c;所以在安装Jenkins之前首先需要安装Java的JDK。 二、安装Jenkins 在Windows平台上面安装Jenkins共有两种方式…

pgsql查询某表所有字段

查询某表所有字段 查询某表所有字段 select * from information_schema.columns where table_schema模式名称 and table_name表名;模式 查询某表字段个数 select count(*) from information_schema.columns where table_schema模式名称 and table_name表名;

RISC-V基础之浮点指令(包含实例)

RISC-V体系结构定义了可选的浮点扩展&#xff0c;分别称为RVF、RVD和RVQ&#xff0c;用于操作单精度、双精度和四倍精度的浮点数。RVF/D/Q定义了32个浮点寄存器&#xff0c;f0到f31&#xff0c;它们的宽度分别为32位、64位或128位。当一个处理器实现了多个浮点扩展时&#xff0…

逻辑卷扩容

背景 服务器有3个逻辑卷&#xff0c;1个是1T&#xff0c;另外两个是500G&#xff0c;需要将500G的合并扩容为1T 操作 df -Th lsblk -f 查看磁盘大小卸载 /approot umount /approot vim /etc/fstab #注释掉/approot mount -a检查是否卸载完成 vgdisplay -v 找到approot所在…

开窗积累之学习更新版

1. 开窗使用1之 count range between current row and current row 将相同排序字段的值进行函数计算 selectsku_id,substr(create_date,1,7) date_month,order_id,create_date,sku_num*price,sum(sku_num*price) over (partition by sku_id order by substr(create_date,1,7)…

Spring Boot多级缓存实现方案

1.背景 缓存&#xff0c;就是让数据更接近使用者&#xff0c;让访问速度加快&#xff0c;从而提升系统性能。工作机制大概是先从缓存中加载数据&#xff0c;如果没有&#xff0c;再从慢速设备(eg:数据库)中加载数据并同步到缓存中。 所谓多级缓存&#xff0c;是指在整个系统架…

纯函数 和 函数柯里化 05 (待补充)

加油&#xff0c;今天周二啦&#xff01;&#x1f60d; 文章目录 前言一、js 的纯函数二、副作用三、纯函数的优势四、JavaScript 柯里化五、柯里化作用 - 让函数的职责单一六、柯里化作用 - 逻辑的复用七、自动柯里化函数&#xff08;我没理解&#xff0c;等我理解了再更&…

如何在洛谷自己出的题中出数据

首先&#xff0c;假如你要加1个数据&#xff1a; 打开Dev-c&#xff08;其他也行&#xff09; 填入输入数据&#xff1a; &#xff08;这个数据只是我编的&#xff09; 将这个东东保存为in文件&#xff08;第一个数据就名为001&#xff0c;第二个002&#xff09;&#xff1a…

2022 robocom 世界机器人开发者大赛-本科组(国赛)

RC-u1 智能红绿灯 题目描述&#xff1a; RC-u1 智能红绿灯 为了最大化通行效率同时照顾老年人穿行马路&#xff0c;在某养老社区前&#xff0c;某科技公司设置了一个智能红绿灯。 这个红绿灯是这样设计的&#xff1a; 路的两旁设置了一个按钮&#xff0c;老年人希望通行马路时会…

没有进度管理的项目,都是在做无用功

在项目管理过程中&#xff0c;最大的挑战之一是确保项目实施与计划保持一致。 项目实施过程是一个相对漫长的过程&#xff0c;其中受到许多因素的影响。如果项目实施没有按照原始项目计划进行&#xff0c;很容易导致项目偏离计划&#xff0c;最终可能导致项目停滞或失败。 当…

Maven出现报错 ; Unable to import maven project: See logs for details错误的多种解决方法

问题现象; IDEA版本&#xff1a; Maven 版本 &#xff1a; 3.3.9 0.检查 maven 的设置 &#xff1a;F:\softeware\maven\apache-maven-3.9.3\conf 检查setting.xml 配置 本地仓库<localRepository>F:\softeware\maven\local\repository</localRepository>镜像…

使用 Python 和 Flask 构建简单的 Restful API 第 1 部分

一、说明 我将把这个系列分成 3 或 4 篇文章。在本系列的最后&#xff0c;您将了解使用flask构建 restful API 是多么容易。在本文中&#xff0c;我们将设置环境并创建将显示“Hello World”的终结点。 我假设你的电脑上安装了python 2.7和pip。我已经在python 2.7上测试了本文…