1.变量
在MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据.
在MySQL数据库中,变量分为系统变量以及用户自定义变量
1.1系统变量
1.1.1系统变量分类
变量由系统定义,不是用户定义,属于服务器层面,启动MySQL服务,生成MySQL服务实例期间,MySQL将为MySQL服务器内存中的系统变量赋值,这些系统变量定义了当前MySQL服务实例的属性,特征.这些变量值要么是编译MySQL时参数的默认值,要么是配置文件中的参数值.
系统变量分为全局系统变量(需添加global关键字)以及会话变量(需添加session关键字).有时也把全局系统变量称为全局变量,有时也会把会话变量称为local变量,如果不写,默认会话级别.静态变量(在MySQL服务实例运行期间它们的值不能使用set动态修改)属于特殊的全局系统变量
每一个MySQL客户机成功连接MySQL服务器后,都会产生与之对应的会话,会话期间,MySQL服务实例会在MySQL服务器内存中生成与该对话对应的会话系统变量,这些会话系统变量的初始值是全局系统变量值的复制
全局系统变量针对于所有会话有效,但不能跨重启
会话系统变量仅针对于当前会话有效,会话期间,当前会话对某个会话系统变量值的修改,不会影响其他会话同一个会话系统变量的值
会话1对某个全局系统变量值的修改,会导致会话2中同一个全局系统变量值的修改
在MySQL中有些系统变量只能是全局的,例如 max_connections 用于限制服务器的最大连接数;有些系统变量作用域既可以是全局又可以是会话,例如 character_set_client 用于设置客户端的字符集;有些系统变量的作用域只能是当前会话,例如 pseudo_thread_id 用于标记当前会话的 MySQL 连接 ID。
1.1.2查看系统变量
查看所有或部分系统变量
sql
#查看所有全局变量
SHOW GLOBAL VARIABLES;
#查看所有会话变量
SHOW SESSION VARIABLES;
#或
SHOW VARIABLES;
#查询部分系统变量
SHOW GLOBAL VARIABLES LIKE 'admin_%'
#查看指定的系统变量的值
SELECT @@global.变量名;
查看指定的会话变量的值
SELECT @@session.变量名;
#或者
SELECT @@变量名;
修改系统变量的值
有些时候,数据库管理员需要修改系统变量的默认值,以便修改当前会话或者MySQL服务实例的属性,特征
方式1:修改MySQL配置文件,继而修改MySQL系统变量的值(该方法需要重启MySQL服务)
方式2:在MySQL服务运行期间,使用set命令重新设置系统变量的值
针对当前实例生效,重启后恢复
sql
#为某个系统变量赋值
#方式1:
SET @@global.变量名 = 变量值;
#方式2:
SET GLOBAL 变量名 = 变量值;
#为某个会话变量赋值
#方式1:
SET @@session.变量名 = 变量值;
#方式2:
SET SESSION 变量名 = 变量值;
1.2用户变量
1.2.1用户变量分类
用户变量是用户自己定义的,作为MySQL编码规范,MySQL中的用户变量以一个@开头,根据作用范围不同,又分为会话用户变量和局部变量
会话用户变量:作用域和会话变量一样,只对当前连接会话有效
局部变量:只在BEGIN和END语句块中有效,局部变量只能在存储过程和函数中使用.
1.2.2会话用户变量
sql
#方式1:"=" 或 ":="
SET @用户变量 = 值;
SET @用户变量 := 值;
#方式2:":=" 或 INTO关键字
SELECT @用户变量 := 表达式 [FROM等子句];
SELECT 表达式 INTO @用户变量 [FROM等子句];
1.2.3局部变量
定义:可以使用DECLARE语句定义一个局部变量
作用域:仅仅在定义它的BEGIN...END中有效
位置:只能放在BEGIN...END中,而且只能放在第一句
sql
BEGIN
#声明局部变量
DECLARE 变量名1 变量数据类型 [DEFAULT 变量默认值];
DECLARE 变量名2,变量名3,... 变量数据类型 [DEFAULT 变量默认值];
#为局部变量赋值
SET 变量名1 = 值;
SELECT 值 INTO 变量名2 [FROM 子句];
END
2.定义条件与处理程序
定义条件是事先定义程序执行过程中可能遇到的问题,,处理程序定义了在遇到问题时应当采取的处理方式,并且保证存储过程或函数在遇到警告或错误时能继续执行.这样可以增强存储过程程序处理问题的能力,避免程序异常停止运行
说明:定义条件和处理程序在存储过程,存储函数中都是支持的
2.1定义条件
定义条件就是给MySQL中的错误码命名,这有助于存储的程序代码更清晰,它将一个错误名字和指定的错误条件关联起来,这个名字可以随后被用在定义处理程序的DECLARE HANDLER语句中
定义条件使用DECLARE语句,语法格式如下
sql
DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)
错误码的说明:
MySQL_error_code和sqlstate_value都可以表示MySQL的错误
MySQL_error_code是数值类型的错误代码
sqlstate_value是长度为5的字符串类型错误代码
例如:在ERROR 1418(HY000)中,1418是MySQL_error_code,HY000是sqlstate_value
sql
#举例1:定义"Field_Not_Be_NULL"错误名与MySQL中违反非空约束的错误类型
#方式1:
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;
#方式2:
DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';
2.2定义处理程序
可以为SQL执行过程中发生的某种类型的错误定义特殊的处理程序,定义处理程序时,使用DECLARE语句的语法如下
sql
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编写的复合语句
sql
#举例
#方法1:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42502' 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';
3.流程控制
解决复杂问题不可能通过一个SQL语句完成,我们需要执行多个SQL操作,流程控制语句的作用就是控制存储过程中SQL语句的执行顺序,是我们完成复杂操作必不可少的一部分,只要是执行的程序,流程就分为三大类.
顺序结构:程序从上往下依次执行
分支结构:程序按条件进行选择执行,从两条或多条路径中选择一条执行
循环结构:程序满足一定条件下,重复执行一组语句
针对于MySQL的流程控制语句主要有3类,注意:只能用于存储程序
条件判断语句:IF语句和CASE语句
循环语句:LOOP,WHILE和REPEAT语句
跳转语句:ITERATE和LEAVE语句
3.1分支结构IF
IF语句的语法结构是:
IF 表达式1 THEN 操作1
ELSEIF 表达式2 THEN 操作2
ELSE 操作N
END IF
sql
DELIMITER //
CREATE PROCEDURE test_if()
BEGIN
DECLARE stu_name VARCHAR(15);
IF stu_name IS NULL
THEN SELECT 'stu_name is null';
END IF;
END //
DELIMITER;
3.2分支结构CASE
CASE语句的语法结构1(类似switch)
CASE 表达式
WHEN 值1 THEN 结果1或语句1(如果是语句需要加分号)
WHEN 值2 THEN 结果2或语句2
....
ELSE 结果n或语句n
END case 如果是放在BEGIN END中需要加上CAS,如果放在SELECT后面不需要
CASE语句的语法结构2(类似多重if)
CASE
WHEN 条件1 THEN 结果1或语句1(如果是语句需要加分号)
WHEN 条件2 THEN 结果2或语句2
....
ELSE 结果n或语句n
END case 如果是放在BEGIN END中需要加上CAS,如果放在SELECT后面不需要
3.3循环结构LOOP
LOOP循环语句用来重复执行某些语句,LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子句),跳出循环过程
LOOP语句的基本格式如下
loop_label: LOOP
循环执行的语句
END LOOP loop_label
其中loop_label表示LOOP语句的标注名称,该参数可以省略
举例1:
使用LOOP语句进行循环操作,id值小于10时将重复执行循环过程
sql
DELIMITER //
CREATE PROCEDURE test_loop()
BEGIN
DECLARE id INT DEFAULT 0;
add_loop:LOOP
SET id = id + 1;
IF id >= 10 THEN LEAVE add_loop;
END IF;
END LOOP add_loop;
SELECT id;
END //
DELIMITER;
CALL test_loop();
3.4循环结构WHILE
WHILE语句创建一个带条件判断的循环过程,WHILE在执行语句时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环,WHILE语句的基本格式如下:
while_label: WHILE 循环条件 DO
循环体
END WHILE while_label;
while_label为WHILE语句的标注名称,如果循环条件结果为真,WHILE语句内的语句或语句群被执行,直至循环条件为假,退出循环
举例1:WHILE语句示例,i值小于10时,将重复执行循环过程,代码如下
sql
DELIMITER //
CREATE PROCEDURE test_while () BEGIN
DECLARE
i INT DEFAULT 0;
WHILE
i < 10 DO
SET i = i + 1;
END WHILE;
SELECT i;
END //
DELIMITER;
CALL test_while ();
3.5循环结构REPEAT
REPEAT语句创建一个带条件判断的循环过程,与WHILE循环不同的是,REPEAT循环首先会执行一次循环,然后再UNTIL中进行表达式的判断,如果满足条件就退出,即END REPEAT,如果条件不满足,则会继续执行循环,直到满足退出条件为止
REPEAT语句的基本格式如下
repeat_label: REPEAT
循环体的语句
UNTIL 结束循环的条件表达式
END REPEAT repeat_label
repeat_label为REPEAT语句的标注名称,该参数可以省略;REPEAT语句内的语句或语句群被重复,直到expr_condition为真
3.6跳转语句LEAVE
LEAVE语句:可以用在循环语句内,或者以BEGIN和END包裹起来的程序题内,表示跳出循环或者跳出程序体的操作,如果你有面向过程的编程语言的使用经验,你可以把LEAVE理解为break
基本格式如下
LEAVE 标记名
其中,label参数表示循环的标志,LEAVE和BEGIN...END或循环一起被使用
举例 1:创建存储过程 "leave_begin ()",声明 INT 类型的 IN 参数 num。给 BEGIN...END 加标记名,并在 BEGIN...END 中使用 IF 语句判断 num 参数的值。
sql
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;
CALL leave_begin(3);
3.7跳转语句ITERATE
ITERATE语句:只能用在循环语句(LOOP,REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处,如果你有面向过程的编程语言的使用经验,你可以把ITERATE理解为continue,意思为再次循环
基本格式如下
ITRATE label
label参数表示循环的标志,ITERATE语句必须跟在循环标志前面
sql
DELIMITER //
CREATE PROCEDURE test_loop ()
BEGIN
DECLARE
num INT DEFAULT 0;
my_loop :
LOOP
SET num = num + 1;
-- num < 10,直接进入下一轮循环
IF num < 10 THEN
ITERATE my_loop;
END IF;
-- num > 15,退出整个循环
IF num > 15 THEN
LEAVE my_loop;
END IF;
END LOOP my_loop;
SELECT
num;
END //
DELIMITER;
4.游标
4.1什么是游标
虽然我们也可以通过筛选条件WHERE和HAVING,或者是限定返回记录的关键字LIMIT返回一条记录,但是却无法在结果集中像指针一样,向前定位一条记录,向后定位一条记录,或者是随意定位到某一条记录,并对记录的数据进行处理.
这个时候就可以用到游标.游标提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构,游标让SQL这种面向集合的语言有了面向过程开发的能力.
在SQL中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针,这里游标充当了指针的作用,我们可以通过操作游标来对数据进行操作.
MySQL中的游标可以在存储过程和函数中使用.
4.2使用游标步骤
游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明
如果我们想要使用游标,一般必须经历四个步骤,不同的DBMS中,使用游标的语法可能略有不同
1.声明游标
在MySQL中,使用DECLARE关键字来声明游标,其语法的基本形式如下
sql
DECLARE cursor_name CURSOR FOR select_statement;
要使用SELECT语句来获取数据结果集,而此时还没有开始遍历数据,这里select_statement代表的是SELECT语句,返回一个用于创建游标的结果集
2.打开游标
语法如下:
sql
OPEN cursor_name;
当我们定义好游标之后,如果想要使用游标,必须先打开游标,打开游标的时候SELECT语句的查询结果就回送到游标工作区,为后面游标的逐条读取结果集中的记录做准备
3.使用游标
语法如下
sql
FETCH cursor_name INTO var_name [, var_name]...
这句的作用是使用cursor_name这个游标来读取当前行,并且将数据保存到var_name这个变量中,游标指针指到下一行,如果游标读取的数据有多个列名,则在INTO关键字后面赋值给多个变量名即可.
4.关闭游标
sql
CLOSE cursor_name