变量
系统变量
系统变量分为全局系统变量(需要添加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;