MySQL基础-变量/流程控制/游标/触发器

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: MySQL基础-变量/流程控制/游标/触发器

MySQL基础-变量/流程控制/游标/触发器


一、变量

35f103b4968760f5c15859d9512eaeb7.png

在MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据

在 MySQL 数据库中,变量分为 系统变量 以及 用户自定义变量


1、系统变量

变量由系统定义,不是用户定义,属于 服务器 层面

启动MySQL服务,生成MySQL服务实例期间,MySQL将为MySQL服务器内存中的系统变量赋值,这些系统变量定义了当前MySQL服务实例的属性、特征


  • 查看变量:
#查看所有全局变量
SHOW GLOBAL VARIABLES;
#查看所有会话变量
SHOW SESSION VARIABLES;
#或 
SHOW VARIABLES;
#查看满足条件的部分系统变量。
SHOW GLOBAL VARIABLES LIKE '%标识符%';
#查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%标识符%';


  • 修改系统变量的值:

方式1:修改MySQL 配置文件 ,继而修改MySQL系统变量的值(该方法需要重启MySQL服务)

方式2:在MySQL服务运行期间,使用“set”命令重新设置系统变量的值

#为某个系统变量赋值
#方式1:
SET @@global.变量名=变量值;
#方式2:
SET GLOBAL 变量名=变量值;
#为某个会话变量赋值
#方式1:
SET @@session.变量名=变量值;
#方式2:
SET SESSION 变量名=变量值;


2、用户变量

  1. 用户变量是用户自己定义的,作为 MySQL 编码规范,MySQL 中的用户变量以 一个“@” 开头
  2. 根据作用范围不同,又分为 会话用户变量 和 局部变量
  3. 会话用户变量:作用域和会话变量一样,只对 当前连接 会话有效
  4. 局部变量:只在 BEGIN 和 END 语句块中有效,局部变量只能在 存储过程和函数 中使用


  • 定义用户变量:
#方式1:“=”或“:=”
SET @用户变量 = 值;
SET @用户变量 := 值;
#方式2:“:=” 或 INTO关键字
SELECT @用户变量 := 表达式 [FROM 等子句];
SELECT 表达式 INTO @用户变量 [FROM 等子句];


  • 定义局部变量:
  1. 定义:可以使用 DECLARE 语句定义一个局部变量
  2. 作用域:仅仅在定义它的 BEGIN … END 中有效
  3. 位置:只能放在 BEGIN … END 中,而且只能放在第一句
BEGIN
#声明局部变量
DECLARE 变量名1 变量数据类型 [DEFAULT 变量默认值];
DECLARE 变量名2,变量名3,... 变量数据类型 [DEFAULT 变量默认值];
#为局部变量赋值
SET 变量名1 = 值;
SELECT 值 INTO 变量名2 [FROM 子句];
#查看局部变量的值
SELECT 变量1,变量2,变量3;
END


  • 案例:声明局部变量,并分别赋值为employees表中employee_id为102的last_name和salary
DELIMITER //
CREATE PROCEDURE set_value(IN emp_id INT)
BEGIN
  DECLARE emp_name VARCHAR(25);
  DECLARE sal DOUBLE(10,2);
  SELECT last_name,salary INTO emp_name,sal
  FROM employees
  WHERE employee_id=emp_id;
  SELECT emp_name,sal;
END //
DELIMITER ;


185c6f8aa98cfc7f2165609b42eaabfe.png


二、流程控制


流程控制语句的作用就是控制存储过程中 SQL 语句的执行顺序,是我们完成复杂操作必不可少的一部分

  • 只要是执行的程序,流程就分为三大类:
  1. 顺序结构 :程序从上往下依次执行
  2. 分支结构 :程序按条件进行选择执行,从两条或多条路径中选择一条执行
  3. 循环结构 :程序满足一定条件下,重复执行一组语句


  • 针对于MySQL 的流程控制语句主要有 3 类:
  1. 条件判断语句 :IF 语句和 CASE 语句(类似switch语句)
  2. 循环语句 :LOOP(类似while(true)语句)、WHILE (while循环)和 REPEAT 语句(do-while语句)
  3. 跳转语句 :ITERATE(continue) 和 LEAVE (break)语句

注:只能用于存储程序

1、分支语句

  • IF 语句的语法结构是:
IF 表达式1 THEN 操作1
[ELSEIF 表达式2 THEN 操作2]……
[ELSE 操作N]
END IF


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


2、循环语句

LOOP语句的基本格式:

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


  • 案例:声明存储过程“update_salary_loop()”,存储过程中实现循环给大家涨薪,薪资涨为原来的1.1倍,直到全公司的平均薪资达到12000结束,并统计循环次数
DELIMITER //
CREATE PROCEDURE update_salary_loop(OUT num INT)
BEGIN
DECLARE avg_salary DOUBLE;
DECLARE loop_count INT DEFAULT 0;
SELECT AVG(salary) INTO avg_salary FROM employees;
label_loop:LOOP
    IF avg_salary >= 12000 THEN LEAVE label_loop;
    END IF;
    UPDATE employees SET salary = salary * 1.1;
    SET loop_count = loop_count + 1;
    SELECT AVG(salary) INTO avg_salary FROM employees;
END LOOP label_loop;
SET num = loop_count;
END //
DELIMITER ;


  • WHILE语句的基本格式:
[while_label:] WHILE 循环条件 DO
循环体
END WHILE [while_label];


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


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


3、跳转语句

  • LEAVE语句:可以把 LEAVE 理解为 break
LEAVE 标记名
#label参数表示循环的标志


  • ITERATE语句:可以把 ITERATE 理解为 continue
ITERATE label


  • 案例:定义局部变量num,初始值为0,循环结构中执行num + 1操作,如果num < 10,则继续执行循环;如果num > 15,则退出循环结构
DELIMITER //
CREATE PROCEDURE test()
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;
    END LOOP my_loop;
END //
DELIMITER ;


三、游标


1、概念

  1. 游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构,游标让 SQL 这种面向集合的语言有了面向过程开发的能力
  2. 在 SQL 中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针。这里游标 充当了指针的作用 ,我们可以通过操作游标来对数据行进行操作


MySQL中游标可以在存储过程和函数中使用

  • 游标优点缺点:
  1. 游标是 MySQL 的一个重要的功能,为 逐条读取 结果集中的数据,提供了完美的解决方案,跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁
  2. 但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行 加锁 ,这样在业务并发量大的时候,不仅会影响业务之间的效率,还会 消耗系统资源 ,造成内存不足,这是因为游标是在内存中进行的处理


2、使用

  • 声明游标:
DECLARE cursor_name CURSOR FOR select_statement;
#适用于 MySQL,SQL Server,DB2 和 MariaDB


注:select_statement 代表的是SELECT 语句,返回一个用于创建游标的结果集

  • 打开游标:
OPEN cursor_name


  • 使用游标:
FETCH cursor_name INTO var_name [, var_name] ...


注:使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可

  • 关闭游标:
CLOSE cursor_name

注:游标会占用系统资源 ,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率


  • 案例:创建存储过程“get_count_by_limit_total_salary()”,函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count
DELIMITER //
CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT
total_count INT)
BEGIN
    DECLARE sum_salary DOUBLE DEFAULT 0; #记录累加的总工资
    DECLARE cursor_salary DOUBLE DEFAULT 0; #记录某一个工资值
    DECLARE emp_count INT DEFAULT 0; #记录循环个数
    #定义游标
    DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
    #打开游标
    OPEN emp_cursor;
    REPEAT
        #使用游标(从游标中获取数据)
        FETCH emp_cursor INTO cursor_salary;
        SET sum_salary = sum_salary + cursor_salary;
        SET emp_count = emp_count + 1;
    UNTIL sum_salary >= limit_total_salary
    END REPEAT;
    SET total_count = emp_count;
    #关闭游标
    CLOSE emp_cursor;
END //
DELIMITER ;


四、触发器


在实际开发中,我们经常会遇到这样的情况:有 2 个或者多个相互关联的表,如 商品信息 和 库存信息 分别存放在 2 个不同的数据表中,我们在添加一条新商品记录的时候,为了保证数据的完整性,必须同时在库存表中添加一条库存记录

创建一个触发器,让商品信息数据的插入操作自动触发库存数据的插入操作。这样一来,就不用担心因为忘记添加库存数据而导致的数据缺失了


1、触发器概念

  1. MySQL从 5.0.2 版本开始支持触发器。MySQL的触发器和存储过程一样,都是嵌入到MySQL服务器的一段程序
  2. 触发器是由 事件来触发 某个操作,这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。所谓事件就是指用户的动作或者触发某项行为。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生了,就会 自动 激发触发器执行相应的操作
  3. 当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时(例如执行添加日志等),可以使用触发器来实现


2、触发器使用

  • 创建触发器:
CREATE TRIGGER 触发器名称
{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
FOR EACH ROW
触发器执行的语句块;


  1. 表名 :表示触发器监控的对象
  2. BEFORE|AFTER :表示触发的时间,BEFORE 表示在事件之前触发;AFTER 表示在事件之后触发
  3. INSERT|UPDATE|DELETE :表示触发的事件
  4. INSERT 表示插入记录时触发/UPDATE 表示更新记录时触发/DELETE 表示删除记录时触发
  5. 当执行语句块只有一个动作时可以不用添加BEGIN-END块


  • 案例:创建名称为before_insert的触发器,向test_trigger数据表插入数据之前,向test_trigger_log数据表中插入before_insert的日志信息
DELIMITER //
CREATE TRIGGER before_insert
BEFORE INSERT ON test_trigger
FOR EACH ROW
BEGIN
INSERT INTO test_trigger_log (t_log)
VALUES('before_insert');
END //
DELIMITER ;
#或者 触发单一动作
CREATE TRIGGER before_insert
BEFORE INSERT ON test_trigger
FOR EACH ROW
BEGIN
INSERT INTO test_trigger_log (t_log)
VALUES('before_insert');


86052b502da6dafddea9709e4c5b53ec.png

  • 查看数据库触发器信息:
#查看当前数据库的所有触发器的定义  
SHOW TRIGGERS\G
#查看当前数据库中某个触发器的定义  
SHOW CREATE TRIGGER 触发器名
#从系统库information_schema的TRIGGERS表中查询“salary_check_trigger”触发器的信息  
SELECT * FROM information_schema.TRIGGERS;


  • 删除触发器:
DROP TRIGGER IF EXISTS 触发器名称;


3、触发器的优缺点

  • 优点:

1、触发器可以确保数据的完整性

2、触发器可以帮助我们记录操作日志

3、触发器还可以用在操作数据前,对数据进行合法性检查

  • 缺点:

1、触发器最大的一个问题就是可读性差

2、相关数据的变更,可能会导致触发器出错

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11天前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
MySQL执行流程
|
2月前
|
存储 自然语言处理 关系型数据库
MySQL 自定义变量并声明字符编码
MySQL 自定义变量并声明字符编码
133 1
|
4月前
|
存储 关系型数据库 MySQL
mysql 使用变量存储中间结果的写法
mysql 使用变量存储中间结果的写法
|
1月前
|
存储 关系型数据库 MySQL
MySQL 8.0特性-自增变量的持久化
【11月更文挑战第8天】在 MySQL 8.0 之前,自增变量(`AUTO_INCREMENT`)的行为在服务器重启后可能会发生变化,导致意外结果。MySQL 8.0 引入了自增变量的持久化特性,将其信息存储在数据字典中,确保重启后的一致性。这提高了开发和管理的稳定性,减少了主键冲突和数据不一致的风险。默认情况下,MySQL 8.0 启用了这一特性,但在升级时需注意行为变化。
|
1月前
|
存储 SQL NoSQL
|
1月前
|
存储 安全 关系型数据库
2024 Mysql基础与进阶操作系列之MySQL触发器详解(21)作者——LJS[你个小黑子这都还学不会嘛?你是真爱粉嘛?真是的 ~;以后请别侮辱我家鸽鸽]
MySQL触发器的使用场景之数据完整性约束、如何具体创建person的日志表、触发器与存储过程的对比与选择、触发器的性能和注意事项等具体操作详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
3月前
|
SQL 缓存 关系型数据库
揭秘MySQL一条SQL语句的执行流程
以上步骤共同构成了MySQL处理SQL语句的完整流程,理解这一流程有助于更有效地使用MySQL数据库,优化查询性能,及时解决可能出现的性能瓶颈问题。
110 7
|
2月前
|
关系型数据库 MySQL 数据处理
企业级应用 mysql 日期函数变量,干货已整理
本文详细介绍了如何在MySQL8.0中使用DATE_FORMAT函数进行日期格式的转换,包括当日、昨日及不同时间段的数据获取,并提供了实际的ETL应用场景和注意事项,有助于提升数据处理的灵活性和一致性。
48 0
|
4月前
|
存储 关系型数据库 MySQL
MySQL 中的触发器数量之谜
【8月更文挑战第31天】
46 0
|
4月前
|
SQL 数据采集 关系型数据库