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;

全局变量的持久化:

相关推荐
0xDevNull3 小时前
MySQL数据冷热分离详解
后端·mysql
科技小花4 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸4 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain4 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希4 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神4 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员5 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java5 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿5 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴5 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存