首页 > 其他分享 >变量、流程控制与游标

变量、流程控制与游标

时间:2023-05-24 23:45:34浏览次数:44  
标签:语句 END 变量 流程 游标 循环 DECLARE SELECT

变量、流程控制与游标

作者:FL

博客:https://www.cnblogs.com/flblogs/

  • 注意:本笔记部分参考尚硅谷-宋红康

1. 变量

MySQL中的变量是一种可以在SQL语句中动态存储和传递数据的机制。与其他编程语言类似,在 MySQL 数据库中,变量分为系统变量以及用户自定义变量

常量:

  1. 字符串常量

  2. 数值常量

  3. 时间日期常量

用户定义变量

用户定义变量使用两个 @ 符号开头,在执行完该语句后存活,只能在当前会话中使用。下面是一个示例:

SET @var1 = 'Hello';
SET @var2 = 5;
SELECT @var1, @var2+10;

以上代码设置了两个变量 @var1 和 @var2,在 SELECT 查询语句中使用这些变量做了简单的计算和输出操作。

系统变量

系统变量由MySQL服务器维护,在全局范围内使用,通常可以通过 SET 或 SHOW 命令来修改或查询其值。例如,我们可以通过以下命令获取 MySQL 的版本信息:

SHOW VARIABLES LIKE 'version%';

以上命令会查询数据库中以“version”开头的所有系统变量,并将它们的名称以及对应的值输出。这样就可以方便地获取MySQL的版本信息。

注意:

在使用变量时,需要遵循MySQL的变量命名规则,比如变量名必须唯一、不能包含特殊字符等等。此外,在某些MySQL版本中还要求变量名必须小写。

流程控制

分支结构之 IF

  • 作用:用于存储过程与函数的分支选择的判断

  • IF 语句的语法结构是:

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

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

  • 特点:

    • 不同的表达式对应不同的操作
    • 使用在begin end中
    • 可以嵌套
    IF val IS NULL 
    	THEN SELECT 'val is null';
    ELSE SELECT 'val is not null';
    
    END IF;
    

案例

-- 使用IF和CASE语句分别完成对customer表的余额 menber_balance 进行判 断,如果余额大于5000,则输出“余额高”;如果余额大于2000,则输出“余额中等”;否则输出“余额偏低”。
SELECT * FROM customer;
-- if
DELIMITER $$

CREATE PROCEDURE p_menber_balance_if(IN sid INT)
BEGIN
	DECLARE balance DOUBLE;
	SELECT menber_balance INTO balance FROM customer WHERE id=sid ;
IF balance > 5000 THEN
    SELECT balance,'余额高' AS '级别';
ELSEIF balance > 2000 THEN
    SELECT balance,'余额中等' AS '级别';
ELSE
    SELECT balance,'余额偏低' AS '级别';
END IF;
END $$

DELIMITER ;

CALL p_menber_balance_if(6);

分支结构之CASE

CASE 语句的语法结构1:

#情况一:类似于switch
CASE 表达式
WHEN 值1 THEN 结果1或语句1(如果是语句,需要加分号) 
WHEN 值2 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后面不需要)
  • 举例1:

使用CASE流程控制语句的第1种格式,判断val值等于1、等于2,或者两者都不等。

CASE val
   WHEN 1 THEN SELECT 'val is 1';
   WHEN 2 THEN SELECT 'val is 2';
   ELSE SELECT 'val is not 1 or 2';
END CASE;
  • 举例2:

使用CASE流程控制语句的第2种格式,判断val是否为空、小于0、大于0或者等于0。

CASE
	WHEN val IS NULL THEN SELECT 'val is null';
	WHEN val < 0 THEN SELECT 'val is less than 0';
	WHEN val > 0 THEN SELECT 'val is greater than 0';
	ELSE SELECT 'val is 0';
END CASE;
  • 举例3:
    使用IF和CASE语句分别完成对customer表的余额 menber_balance 进行判 断,如果余额大于5000,则输出“余额高”;如果余额大于2000,则输出“余额中等”;否则输出“余额偏低”。
DELIMITER $$

CREATE PROCEDURE p_menber_balance_case(IN sid INT)
BEGIN
	DECLARE balance DOUBLE;
	SELECT menber_balance INTO balance FROM customer WHERE id=sid ;
CASE 
WHEN balance > 5000 THEN
    SELECT balance,'余额高' AS '级别';

WHEN balance > 2000 THEN
    SELECT balance,'余额中等' AS '级别';

ELSE
    SELECT balance,'余额偏低' AS '级别';
END CASE;
END $$

DELIMITER ;

CALL p_menber_balance_case(6);

循环结构之LOOP

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

LOOP语句的基本格式如下:

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

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

举例1:

使用LOOP语句进行循环操作,id值小于10时将重复执行循环过程。

循环结构之WHILE

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

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

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

循环结构之REPEAT

REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT 循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止。

REPEAT语句的基本格式如下:

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

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

对比三种循环结构:

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

跳转语句之LEAVE语句

LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。如果你有面向过程的编程语言的使用经验,你可以把 LEAVE 理解为 break。

基本格式如下:

LEAVE 标记名

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

举例1:创建存储过程 “leave_begin()”,声明INT类型的IN参数num。给BEGIN...END加标记名,并在BEGIN...END中使用IF语句判断num参数的值。

  • 如果num<=0,则使用LEAVE语句退出BEGIN...END;
  • 如果num=1,则查询“employees”表的平均薪资;
  • 如果num=2,则查询“employees”表的最低薪资;
  • 如果num>2,则查询“employees”表的最高薪资。

IF语句结束后查询“employees”表的总人数。

DELIMITER //

CREATE PROCEDURE leave_begin(IN num INT)

	begin_label: BEGIN
		IF num<=0 
			THEN LEAVE begin_label;
		ELSEIF num=1 
			THEN SELECT AVG(salary) FROM employees;
		ELSEIF num=2 
			THEN SELECT MIN(salary) FROM employees;
		ELSE 
			SELECT MAX(salary) FROM employees;
		END IF;
		
		SELECT COUNT(*) FROM employees;
	END //


DELIMITER ;

跳转语句之ITERATE语句

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

语句基本格式如下:

ITERATE label

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

举例: 定义局部变量num,初始值为0。循环结构中执行num + 1操作。

  • 如果num < 10,则继续执行循环;
  • 如果num > 15,则退出循环结构;
DELIMITER //

CREATE PROCEDURE test_iterate()

BEGIN
	DECLARE num INT DEFAULT 0;
	
	my_loop:LOOP
		SET num = num + 1;
	
		IF num < 10 
			THEN ITERATE my_loop;
		ELSEIF num > 15 
			THEN LEAVE my_loop;
		END IF;
	
		SELECT '第'+num;
	
	END LOOP my_loop;

END //

DELIMITER ;

总结

游标

引入

虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录,但是,却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是随意定位到某一条记录,并对记录的数据进行处理。

这个时候,就可以用到游标。游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。游标让 SQL 这种面向集合的语言有了面向过程开发的能力。

介绍

  • 游标(Cursor)是一种数据库对象,它允许程序对结果集进行遍历和操作。在MySQL中,游标可以用于存储过程和函数中,以便在处理结果集时进行更精细的控制。

  • 游标可以用于以下情况:
    1. 遍历结果集:游标可以让程序逐行遍历结果集,并对每一行进行操作。
    2. 逐行处理数据:游标可以让程序对每一行数据进行特定的操作,例如计算总和、平均值等。
    3. 处理复杂查询:当查询语句比较复杂时,游标可以让程序更好地控制结果集,以便进行更复杂的操作。

  • 在MySQL中,游标的使用需要注意以下几点:
    1. 游标必须在存储过程或函数中声明,并且必须在使用前打开。
    2. 游标必须在使用后关闭,并且必须释放相关资源。
    3. 游标只能用于SELECT语句,不能用于INSERT、UPDATE或DELETE语句。
    4. 游标的使用可能会影响性能,因此应该谨慎使用。

游标相关操作

第一步,声明游标

  • 在MySQL中,使用DECLARE关键字来声明游标,其语法的基本形式如下:
DECLARE cursor_name CURSOR FOR select_statement; 
  • 要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集。

第二步,打开游标

  • 打开游标的语法如下:
OPEN cursor_name
  • 当我们定义好游标之后,如果想要使用游标,必须先打开游标。打开游标的时候 SELECT 语句的查询结果集就会送到游标工作区,为后面游标的逐条读取结果集中的记录做准备。

第三步,使用游标(从游标中取得数据)

  • 语法如下:
FETCH cursor_name INTO var_name [, var_name] ...
  • 这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。
FETCH cur_emp INTO emp_id, emp_sal ;

注意:游标的查询结果集中的字段数,必须跟 INTO 后面的变量数一致,否则,在存储过程执行的时候,MySQL 会提示错误。

第四步,关闭游标

CLOSE cursor_name

有 OPEN 就会有 CLOSE,也就是打开和关闭游标。当我们使用完游标后需要关闭掉该游标。因为游标会占用系统资源,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标的操作,会释放游标占用的系统资源。

关闭游标之后,我们就不能再检索查询结果中的数据行,如果需要检索只能再次打开游标。

案例:

-- 使用游标创建一个存储过程,统计商品单价大于100的记录的数量
SELECT * FROM goods;
DELIMITER //

CREATE PROCEDURE count_expensive_goods()
BEGIN
	-- 创建 用于接收游标值的变量
	DECLARE u_price DOUBLE DEFAULT 0;# 定义临时变量
  DECLARE done INT DEFAULT FALSE;# 定义退出条件标识符
  DECLARE count INT DEFAULT 0;# 定义计数
  -- 声明游标
  DECLARE cur CURSOR FOR SELECT unit_price FROM goods WHERE unit_price > 100;
  -- 定义处理方式
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
-- 打开游标
  OPEN cur;
-- 在循环中使用游标
  read_loop: LOOP
    FETCH cur INTO u_price; # 需要一个临时变量存储游标指向的值
    IF done THEN
      LEAVE read_loop;
    END IF;

    SET count = count + 1;
  END LOOP;
-- 关闭游标
  CLOSE cur;

  SELECT count;
END//

DELIMITER ;

CALL count_expensive_goods();

异常处理

介绍

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

定义条件

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

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

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

错误码的说明:
如下图,推荐使用终端或百度查看完整错误码。

  • MySQL_error_codesqlstate_value都可以表示MySQL的错误。
    • MySQL_error_code是数值类型错误代码。
    • sqlstate_value是长度为5的字符串类型错误代码。(图像界面可能没有)

例:

-- 错误处理

INSERT INTO goods (id, goods_name, supplier_id, goods_type, banner, introduce, unit_price, amount, goods_memo)
    VALUES (22,'农夫山泉', 1, '饮用水', 'banner.jpg', 'Product A description', 2.5, 100, 'Memo'); # 插入id,主键重复错误
		
-- 定义条件
# 格式:DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)
-- 方式一:错误码
DECLARE Duplicate_Entry CONDITION FOR 1062;
-- 方式二:错误条件
DECLARE Duplicate_Entry CONDITION FOR SQLSTATE'23000';

定义处理程序

可以为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';

例:

-- 定义条件
# 格式:DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)
-- 方式一:错误码
DECLARE Duplicate_Entry CONDITION FOR 1062;
-- 方式二:错误条件
DECLARE Duplicate_Entry CONDITION FOR SQLSTATE'23000';

-- 创建一个通过id插入商品的存储过程,如果重复就不加入,返回-1并退出
DROP PROCEDURE IF EXISTS insert_good_by_id;
DELIMITER $
CREATE PROCEDURE insert_good_by_id(
    IN p_id INT(11),
    IN p_goods_name VARCHAR(50),
    IN p_supplier_id INT(11),
    IN p_goods_type CHAR(20),
    IN p_banner VARCHAR(255),
    IN p_introduce VARCHAR(255),
    IN p_unit_price DECIMAL(11,2),
    IN p_amount INT(10),
    IN p_goods_memo VARCHAR(300))
	BEGIN
		# 声明处理程序
		# 方式一
		#DECLARE EXIT HANDLER FOR 1062 SET @err_code = -1;
		# 方式二
		#DECLARE EXIT HANDLER FOR SQLSTATE '23000' SET @err_code = -1;
		# 方式三
		DECLARE duplicate_entry CONDITION FOR 1062;
		DECLARE EXIT HANDLER FOR duplicate_entry SET @err_code = -1;
		
		INSERT INTO goods (id, goods_name, supplier_id, goods_type, banner, introduce, unit_price, amount, goods_memo)
    VALUES (p_id, p_goods_name, p_supplier_id, p_goods_type, p_banner, p_introduce, p_unit_price, p_amount, p_goods_memo);
		
		END $
DELIMITER ;
		CALL insert_good_by_id(22,'农夫山泉', 1, '饮用水', 'banner.jpg', 'Product A description', 2.5, 100, 'Memo');
		SELECT @err_code;

标签:语句,END,变量,流程,游标,循环,DECLARE,SELECT
From: https://www.cnblogs.com/flblogs/p/17389066.html

相关文章

  • APP中RN页面渲染流程-ReactNative源码分析
    在APP启动后,RN框架开始启动。等RN框架启动后,就开始进行RN页面渲染了。RN页面原生侧页面渲染的主要逻辑实现是在RCTUIManager和RCTShadowView完成的。通过看UIMananger的源码可以看到,UIMananger导出给JS端的API接口在对UI的操作上,基本都会同时对View和ShadowView进行操作。......
  • gitlab--内置的环境变量、自定义环境变量
    自定义环境变量gitlab给我们内置了很多的变量,但有时候满足不了我们的需求,例如我们需要往某个私有仓库推送镜像,需要账号和密码进行登录。这时候我们不想把密码写在.gitlab-ci.yml文件里面。我们就可以自定义一个环境变量来使用了。先来定义一个变量,设置-》CI/CD-》变量在.g......
  • 聊聊栈帧中的局部变量表和操作数栈
    前置阅读【图解JVM内存模型及JAVA程序运行原理】:https://developer.aliyun.com/article/1218034?utm_content=g_1000372435 本文内容和【图解JVM内存模型及JAVA程序运行原理】一文中的“程序样例执行详解”相关。 代码示例:publicintoperandStackExample(inta,intb){......
  • 【JavaScript用法】JavaScript(JS)的基本语法(JS数据类型,JS变量,JS运算符,JS流程控制语句
    JavaScript(JS)的基本语法目录JavaScript(JS)的基本语法一.与html结合方式二.注释三.数据类型:四.变量五.运算符(和Java有点类似)六.流程控制语句(和JAVA 类似):七.JS特殊语法:一.与html结合方式       1.内部JS:定义<script>,标签体内容就是js代码(可以理解为和html......
  • 边缘计算AI硬件智能分析网关V1版的接入流程与使用步骤
    我们的AI边缘计算网关硬件——智能分析网关目前有两个版本:V1版与V2版,两个版本都能实现对监控视频的智能识别和分析,支持抓拍、记录、告警等,在AI算法的种类上和视频接入上,两个版本存在些许的区别。V1的基础算法有人体检测、区域入侵检测、戴口罩识别、安全帽识别;V2目前有15种算法,包括......
  • QTLtools 协变量文件说明(covariate)
    协变量格式如下所示:注意事项:缺失值用NA表示;接受定性和定量的协变量;定量协变量用数值型表示;定性协变量用非数值型表示,类似于上图的A,B,C。定量和定性的判断依据是有没有等级关系,比如年龄属于定量,比如地区属于定性。需要注意的是,只要是定性的变量,都不能用数值表示,不然会被当成......
  • ANR问题一般分析流程
    ANR问题成因类别 分析步骤确认友商如果是三方应用的anr问题且必现问题或高概率发生,先确认pixel原生机是否可以同样复现,以及友商手机可否复现,分为4种情况。如果判断为三方应用的问题,可转三方质量商务处理并适当贴一些原因分析。三方应用情况分类 我司原......
  • 项目级服务器数据迁移流程
    项目级服务器数据迁移流程创建时间: 2022/09/24更新时间: 2022/09/24编辑: 徐俊杰项目级服务器数据迁移流程以下操作针对最终迁移目标为移动机房托管的硬件服务器,其它服务器进具备参考价值```text183.213.16.9dtsiteqwer4321asdf```一、目录必要拷贝注意:部分内容可......
  • 流程表单JavaScript代码
    ----订单流程-----------//表单加载初始化时functionpreinit(){}//表单加载完成,isrun代表流程是否流转中1-是,0-否functionLoaded(isrun){$("#om_order_status").attr("disabled","disabled");......
  • 变量的存储 -- 栈和堆的区别
    引用:彻底搞懂JS闭包各种坑-简书(jianshu.com)1.js中基本变量和对象的内存存储:      2. ......