MySQL数据库,变量、流程控制与游标

变量

系统变量

系统变量分为全局系统变量(需要添加global关键字)以及会话系统变量(需要添加session关键字)有时将全局系统变量简称为全局变量,将会话系统变量称为local变量。如果不写,默认会话级别。静态变量属于特殊的全局系统变量。

注:

  • 全局系统变量针对于所有的会话(连接)有效,但不能跨重启。

  • 会话系统变量仅针对于当前会话(连接)有效,会话期间,当前会话对某个会话系统变量值的修改,不会影响其他会话同一个会话系统变量的值。

  • 会话1对某个全局变量值的修改会导致会话2中同一个全局变量值的修改。

查看系统变量

查看所有全局变量:

SHOW GLOBAL VARIABLES [LIKE '......'];

查看所有会话变量:

SHOW SESSION VARIABLES [LIKE '......'];

SHOW VARIABLES;-- 默认会话级别

MySQL中的系统变量以两个@开头,其中@@global仅用于标记全局系统变量,@@session仅用于标记会话系统变量。@@后如果未跟global或session,@@会首先标记会话系统变量,如果会话系统变量不存在,则标记全局系统变量。

查看指定的全局系统变量的值:

SELECT @@global.变量名;

查看指定的会话变量的值

SELECT @@session.变量名;

或者

SELECT @@变量名;

修改系统变量的值

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

方式二:在MySQL服务运行期间,使用SET命令重新设置系统变量的值。

为某个系统变量赋值

SET @@global.变量名 = 变量值;

SET GLOBAL 变量名 = 变量值;

针对于当前的数据库实例有效,一旦重启MySQL服务就失效。

为某个会话变量赋值

SET @@session.变量名 = 变量值;

SET SESSION 变量名 = 变量值;

对当前会话有效

用户变量

用户变量是用户自己定义的,作为MySQL编码规范,MySQL中的用户变量以一个@开头。根据作用范围的不同,又分为会话用户变量和局部变量。

  • 会话用户变量:作用域和会话变量一样,只对当前连接的会话有效。

  • 局部变量:只在BEGIN和END语句中有效。局部变量只能在存储过程和存储函数中使用。

会话用户变量

变量的定义:

方式一:使用SET的方式

SET @用户变量 = 值;

SET @用户变量 := 值;

方式二:查询时使用INTO的方式

SELECT 表达式 INTO @用户变量 [FROM等子句];

SELECT @用户变量 :=表达式 [FROM等子句];

查看用户变量的值(查看、比较、运算等)

SELECT @用户变量

SELECT @用户变量......

局部变量

定义:使用DECLARE语句定义一个局部变量。

作用域:只在BEGIN和END中间有效。

位置:只能放在BEGIN和END中,且只能放在第一句。

BEGIN

声明局部变量

DECLARE 变量名 变量数据类型 [DEFAULT 变量默认值];

DECLARE 变量名,变量名,...... 变量数据类型 [变量默认值];

为局部变量赋值

SET 变量名 = 值;

SELECT 值 INTO 变量名 [FROM 子句];

查看局部变量的值

SELECT 变量名,变量名,......;

END

注:局部变量如果没有DEFAULT子句,初始值为NULL。

定义条件与处理程序

定义条件是事先定义程序执行过程中可能遇到的问题,处理程序定义了在遇到问题时的处理方式,并且保证存储过程或存储函数在遇到警告时能继续执行。

定义条件

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

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

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

关于错误码:

注:如果错误码是由数字组成的字符串,为了防止发生隐式转换,要在此错误码前加上SQLSTATE。

定义处理程序

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

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

关于处理方式、错误类型、处理语句:(打字好累,截图偷懒)

例:使用CONTINUE的方式:(last_name字段有非空约束)

sql 复制代码
DELIMITER $

CREATE PROCEDURE test_exception()

BEGIN

DECLARE CONTINUE HANDLER FOR 1048 SET @prc_val = -1;

SET @ss = 1;

UPDATE test_1 SET last_name = NULL WHERE id = 1;

SET @ss = 9;

UPDATE test_1 SET last_name = 'Peter' WHERE id = 1;

END $

DELIMITER ;



CALL test_exception();

SELECT @ss,@prc_val;

结果为:

使用EXIT的方式:(id字段有唯一性约束,表中已有id为2的记录)

sql 复制代码
DELIMITER $

CREATE PROCEDURE test_bb()

BEGIN

DECLARE EXIT HANDLER FOR 1062 SET @pro_val = 66;

SET @x = 1;

INSERT INTO test_1

VALUES(2,'Tony','@hyhi',5000);

SET @x = 9;

END $

DELIMITER ;



CALL test_bb();



SELECT @x,@pro_val;

结果为

流程控制

流程控制语句的作用是控制存储过程或存储函数中SQL语句的执行顺序。流程分为三类:

顺序结构:程序从上往下依次执行。

分支结构:程序按条件进行选择执行,从多条语句中选择其中一条执行。

循环结构:程序满足一定条件下,重复执行一组语句。

流程控制语句主要有三类:

条件判断语句:IF语句和 CASE语句

循环语句:LOOP、WHILE和REPEAT语句

跳转语句:ITERATE、LEAVE语句

分支结构之IF

IF语句的语法结构是

IF search_condition THEN

statement_list

ELSE IF search_condition THEN

statement_list

......

ELSE

statement_list

END IF;

根据表达式的结果为TRUE或FALSE执行相应的语句。使用在BEGIN......END中。

分支语句之CASE

CASE的语句格式有两种:

用法与Java中和C语言的流程控制差不多,套模板就可以。

循环结构之LOOP

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

LOOP语句的格式:

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

例:当id < 10时将重复执行循环过程。

sql 复制代码
DELIMITER  $

CREATE PROCEDURE test_loop()

BEGIN

DECLARE id INT DEFAULT 0;

aa:LOOP

    SET id = id + 1;

    IF id >= 10 THEN

        LEAVE aa;

    END IF;

END LOOP aa;

SELECT id;

END $

DELIMITER ;



CALL test_loop;

例:将所有的员工的工资提高1.1倍,如果没有达到公司平均工资3500以上,继续提高1.1倍,......直到公司平均工资达到3500以上。

sql 复制代码
DELIMITER  $

CREATE PROCEDURE test_loop_1(OUT num INT)

BEGIN

DECLARE avg_sal DECIMAL(7,2);

DECLARE loop_count INT DEFAULT 0;

SELECT AVG(sal) INTO avg_sal FROM emp_loop;

aaa: LOOP

    IF avg_sal >= 3500 THEN

        LEAVE aaa;

    END IF;-- 跳出循环的条件

    UPDATE emp_loop SET sal = sal * 1.1;-- 涨薪

    SELECT AVG(sal) INTO avg_sal FROM emp_loop;-- 更新员工平均工资

    SET loop_count = loop_count + 1;-- 更新循环次数

END LOOP aaa;

SELECT loop_count INTO num;

END $

DELIMITER ;



SET @x = 0;

CALL test_loop_1(@x);

SELECT @x;

循环结构之WHILE

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

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

和C语言与Java中的while循环差不多。

例:(没有使用循环标签)

sql 复制代码
DELIMITER $

CREATE PROCEDURE test_while()

BEGIN

DECLARE num INT DEFAULT 0;

WHILE num <= 10 DO

    SET num = num + 1;

END WHILE;

SELECT num;

END $

DELIMITER ;



CALL test_while();

例:将所有的员工的工资降低到0.8倍,如果没有达到公司平均工资2500以下,继续提高降低到0.8倍,......直到公司平均工资达到2500以下。

sql 复制代码
DELIMITER  $

CREATE PROCEDURE test_while_1(OUT num INT)

BEGIN

DECLARE avg_sal DECIMAL(7,2);

DECLARE loop_count INT DEFAULT 0;

SELECT AVG(sal) INTO avg_sal FROM emp_loop;

WHILE avg_sal > 2500 DO

    UPDATE emp_loop SET sal = sal * 0.8;

    SELECT AVG(sal) INTO avg_sal FROM emp_loop;

    SET loop_count = loop_count + 1;

END WHILE;

SELECT loop_count INTO num;

END $

DELIMITER ;



SELECT AVG(sal) FROM emp_loop;



SET @s = 0;

CALL test_while_1(@s);

SELECT @s;

循环结构之REPEAT

REPEAT语句创建一个带条件判断的循环过程。与WHILE不同的是,REPEAT循环会首先执行一次循环,然后在UNTIL中进行表达式的判断,如果满足条件就退出。类似于C语言和Java中的do while循环。

REPEAT就不写例子了,与前面的例子基本一样,只是格式不一样。

跳转结构之LEAVE语句

运行了LEAVE语句后,跳出整个循环。

格式:

LEAVE [label]

其中,label表示某个循环的标志。也可以给BEGIN ...... END赋上标签,表示跳出此BEGIN ...... END语句

相当于C语言和Java中的break语句。

跳转结构之ITERATE

ITERATE语句:只能用在循环语句中,表示跳过此次循环,进入到下一次循环。

格式:

ITERATE [label]

相当于C语言和Java中的continue语句。

游标

游标提供了一种灵活的操作方式,能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。

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

游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明。

游标使用步骤:

①声明游标:

②打开游标:

③使用游标:

④关闭游标:

注:

游标的作用有点类似于Java的迭代器Iterator。每执行一次FETCH操作就类似于执行一次迭代器中的next方法的操作,返回当前指向的元素后,将指针指向下一个元素(即逐条读取,通常与循环一起使用)。

例:按员工从大到小开始计算,逐个累加员工工资直到总和达到20000.

sql 复制代码
DELIMITER $

CREATE PROCEDURE test_yb(IN total_sal DECIMAL(7,2),OUT total_count INT)

BEGIN

#声明局部变量

DECLARE sum_sal DECIMAL(7,2) DEFAULT 0.0;-- 记录累加的工资总和

DECLARE emp_sal DECIMAL(7.2) DEFAULT 0.0;-- 记录每一个员工的工资

DECLARE emp_count INT DEFAULT 0;-- 记录累加的人数

-- 声明游标

DECLARE emp_cursor CURSOR FOR SELECT sal FROM emp ORDER BY sal DESC;

-- 打开游标

OPEN emp_cursor;

-- 使用游标

REPEAT

    FETCH emp_cursor INTO emp_sal;

    SET sum_sal = sum_sal + emp_sal;

    SET emp_count = emp_count + 1;

UNTIL sum_sal >= total_sal END REPEAT;

SET total_count = emp_count;

-- 关闭游标

CLOSE emp_cursor;

END $

DELIMITER ;



SET @count_emp = 0;

CALL test_yb(20000,@count_emp);

SELECT @count_emp;

全局变量的持久化:

相关推荐
Elastic 中国社区官方博客8 分钟前
Elasticsearch 和 Kibana 8.16:Kibana 获得上下文和 BBQ 速度并节省开支!
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
晴天のVlog10 分钟前
Fastapi使用MongoDB作为数据库
数据库·python·mongodb·fastapi
三杯温开水11 分钟前
基于 CentOS7.6 的 Docker 下载常用的容器(MySQL&Redis&MongoDB),解决拉取容器镜像失败问题
redis·mysql·docker
chusheng184023 分钟前
Python 正则表达式进阶用法:量词与范围
python·mysql·正则表达式
Desmend__23 分钟前
正则表达式那些事儿
数据库·mysql·正则表达式
袁庭新40 分钟前
LuaRocks如何安装数据库驱动?
java·数据库·redis·lua·luarocks·袁庭新
hummhumm1 小时前
第 10 章 - Go语言字符串操作
java·后端·python·sql·算法·golang·database
Narutolxy1 小时前
从 MySQL 5.7 到 8.0:理解 GROUP BY 的新规则与实战优化20241112
数据库
chusheng18401 小时前
Python 正则表达式进阶用法:分组与引用详解
数据库·python·正则表达式
喵叔哟2 小时前
重构代码之移动字段
java·数据库·重构