MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据,或则输出最终的结果数据
在MySQL数据库中,变量分为系统变量以及用户自定义变量
每一个MySQL客户机成功连接MySQL服务器后,都会产生与之对应的会话。会话期间,MySQL服务实例会在MySQL服务器内存中生成与该会话对应的会话系统变量,这些会话系统变量的初始值是全局系统变量值的复制
SHOW GLOBAL VARIABLES;
SHOW SESSION VARIABLES;
SHOW VARIABLES;
SHOW GLOBAL VARIABLES LIKE 'admin%';
SHOW VARIABLES LIKE 'character_%';
查看指定系统变量
SELECT @@global.MAX_CONNECTIONS;
SELECT @@session.character_set_client;
#先查找会话系统变量再查找全局系统变量
SELECT @@character_set_client;
修改系统变量的值
针对当前数据库的实例有效,但一旦重启MySQL服务,就失效了
SET @@global.MAX_CONNECTIONS=161;
SET GLOBAL MAX_CONNECTIONS=171;
针对当前会话是有效的的,一旦结束会话,重新建立起新的会话,就失效了
SET @@session.character_set_client='gbk';
SET SESSION character_set_client='gbk';
用户变量是由用户自己定义的。MySQL中的用户变量以一个@开头。根据作用范围不同,可分成会话用户变量和局部变量
SET @m1 = 1;
SET @m2 := 2;
SET @sum := @m1+@m2;
SELECT @sum;
SELECT @count:= COUNT(*) FROM emp;
SELECT @count;
SELECT AVG(salary) INTO @avg_sal
FROM emp;
SELECT @avg_sal;
定义:使用DECLEAR语句定义一个局部变量
作用域:仅仅在定义它的BEGIN…END中有效(使用在存储过程和存储函数中)
位置:只能放在BEGIN…END中,并且只能放在第一句
DECLEAR 变量名 类型【default 值】;如果没有DEFAULT子句,初始值为NULL
DELIMITER //
CREATE PROCEDURE test_val()
BEGIN
DECLARE a INT DEFAULT 0;
DECLARE b INT;
DECLARE emp_name VARCHAR(25);
SET a =1;
SET b:=2;
SELECT last_name INTO emp_name
FROM emp WHERE employee_id=101;
SELECT a,b,emp_name;
END //
DELIMITER ;
CALL test_val();
作用域 | 定义位置 | 语法 | |
---|---|---|---|
用户会话变量 | 当前会话 | 会话的任意的地方 | 加@符号,不用指定类型 |
局部变量 | 定义它的BEGIN…END中 | BEGIN…END的第一句化 | 一般不加@,需要指定而类型 |
定义条件:事先定义程序执行过程中可能遇到的问题
处理程序:定义了在遇到问题时应当采取的处理方式,并保证存储过程或函数在遇到警告或错误时能继续执行
定义条件:就是给MySQL中的错误码命名,有助于存储的程序代码更轻西。其将一个错误名字和指定的错误条件关联起来,这个名字可以随后被用在定义处理程序的DECLEAR HANDLER语句中
DECLARE 错误名称 CONDITION FOR 错误码(错误条件)
错误码:
DECLARE Fileld_NOT_BE_NULL CONDITION FOR 1048;
DECLARE Fileld_NOT_BE_NULL CONDITION FOR SQLSATATE '23000';
可以为SQL职系那个过程中发生的某种类型的错误定义特殊的处理程序
DECLARE 处理方式 HANDLER FOR 错误类型 处理语句
处理方式
错误类型
处理语句
DECLARE CONTINUE HANDLER FOR SQLSTATE '42s02' SET @info='NO_SUCH_TABLE';
声明处理程序需要在BEGIN中进行处理程序
流程控制语句的作用控制存储过程中SQL语句的执行顺序。根据执行的程序,流程可以分为
针对三种不同的MySQL流程控制语句分为3类
IF 表达式1 THEN 操作1
[ELSEIF 表达式2 THEN 操作2]...
[ELSE 操作N]
END IF
DELIMITER //
CREATE PROCEDURE test_if()
BEGIN
DECLARE stu_name VARCHAR(20);
IF stu_name IS NULL
THEN SELECT 'stu_name is NULL';
END IF;
END //
DELIMITER ;
CALL test_if();
DROP PROCEDURE test_if;
CASE 语法结构
CASE 表达式
WHEN 值1 THEN 结果1或语句1
WHEN 值2 THEN 结果2或语句2
...
ELSE 结果n或语句n
END [case] 如果放在bigin end中需要加上case,如果放在select后面则不需要
CASE
WHEN 条件1 THEN 结果1或语句1
WHEN 条件2 THEN 结果2或语句2
...
ELSE 结果n或语句n
END [case] 如果放在bigin end中需要加上case,如果放在select后面则不需要
DELIMITER //
CREATE PROCEDURE test_case()
BEGIN
DECLARE var INT DEFAULT 2;
CASE var
WHEN 1 THEN SELECT 'var==1';
WHEN 2 THEN SELECT 'var==2';
WHEN 3 THEN SELECT 'var==3';
ELSE SELECT 'other value';
END CASE;
END //
DELIMITER ;
CALL test_case();
DELIMITER //
CREATE PROCEDURE test_case2()
BEGIN
DECLARE var INT DEFAULT 10;
CASE
WHEN var>=100 THEN SELECT '三位数';
WHEN var>=10 THEN SELECT '二位数';
ELSE SELECT '个位数';
END CASE;
END //
DELIMITER ;
CALL test_case2();
LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子句),跳出循环的过程
[loop_label:] LOOP
循环执行的语句
END LOOP[loop_label]
DELIMITER //
CREATE PROCEDURE test_loop()
BEGIN
DECLARE num INT DEFAULT 1;
loop_label:LOOP
SET num=num+1;
IF num>=10 THEN LEAVE loop_label;
END IF;
END LOOP loop_label;
SELECT num;
END //
DELIMITER ;
CALL test_loop();
loop_label可以省略
while语句创建一个带条件判断的循环过程。WHILE在执行语句时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环。
[while_label] WHILE 循环条件 DO
循环体
END WHILE[while_label];
凡是循环结构,一定具有四个要素
DELIMITER //
CREATE PROCEDURE test_while()
BEGIN
DECLARE num INT DEFAULT 1;
WHILE num<=10 DO
SET num=num+1;
END WHILE;
SELECT num;
END //
CALL test_while();
REPEAT创建一个带条件判断的循环过程。与WHILE循环不同,REPEAT循环首先执行一次循环,然后在UNTIL中进行表达式判断,如果满足条件就退出,即END REPEAT;如果条件不满足,则会继续执行循环,知道满足退出条件为止
[repeat_label:]REPEAT
循环体的语句
UNTIL 结束循环的条件表达式
END REPEAT [repeat_label]
DELIMITER //
CREATE PROCEDURE test_repeat()
BEGIN
DECLARE num INT DEFAULT 1;
REPEAT
SET num = num+1;
UNTIL num >= 10
END REPEAT;
SELECT num;
END //
DELIMITER ;
call test_repeat()
LEAVE语句:可以在循环语句中,或则以BEGIN和END包裹起来的程序体内,表示跳出循环或则跳出程序体的操作,相当于break
LEAVE 标记名
DELIMITER //
CREATE PROCEDURE test_leave(IN num INT)
begin_label:BEGIN
IF num<=0
THEN LEAVE begin_label;
ELSEIF num=1
THEN SELECT AVG(salary) FROM emp;
ELSEIF num=2
THEN SELECT MIN(salary) FROM emp;
ELSE
SELECT MAX(salary) FROM emp;
END IF;
SELECT COUNT(*) FROM emp;
END //
DELIMITER ;
call test_leave(3);
只能在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处,相当于continue
ITERATE label
DELIMITER //
CREATE PROCEDURE test_iterate ()
begin_label:BEGIN
DECLARE num INT DEFAULT 0;
loop_label:LOOP
SET num=num+1;
IF num<10
THEN ITERATE loop_label;
ELSEIF num>15
THEN LEAVE loop_label;
END IF;
SELECT num;
END LOOP;
END //
DELIMITER ;
CALL test_iterate();
游标:提供了一种灵活的操作方式,可以对集合中的每一条记录进行定位,并对指定的记录中的数据进行操作的数据结构
游标让SQL这种面向集合的语言有了面向过程开发的能力
游标充当了指针的作用。在SQL中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针,可以通过操作游标来对数据进行操作
MySQL中游标可以在存储过程和函数中使用
需要放在变量声明的下面
DECLARE cursor_name CURSOR FOR selete_statement
DECLARE cursor_name CURSOR IS selete_statement
OPEN cursor_name
FETCH cursor_name INTO var_name1,...,var_namen
游标的查询结果集中的字段数,必须跟INTO后面的变量数一致,否则存储过程执行的时候,MySQL会提示错误
CLOSE cursor_name
因为游标会占用系统资源,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率
DELIMITER //
CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_today_salary DOUBLE,OUT total_count INT)
BEGIN
DECLARE sum_sal DOUBLE DEFAULT 0.0;
DECLARE emp_sal DOUBLE;
DECLARE emp_count INT DEFAULT 0;
DECLARE emp_cursor CURSOR FOR SELECT salary FROM emp ORDER BY salary 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>= limit_today_salary
END REPEAT;
SET total_count=emp_count;
CLOSE emp_cursor;
END //
DELIMITER ;
CALL get_count_by_limit_total_salary(200000,@total_count);
SELECT @total_count;
游标为逐条读取结果集中的数据,提供了完美的解决方案
sum_sal DOUBLE DEFAULT 0.0;
DECLARE emp_sal DOUBLE;
DECLARE emp_count INT DEFAULT 0;
DECLARE emp_cursor CURSOR FOR SELECT salary FROM emp ORDER BY salary 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>= limit_today_salary
END REPEAT;
SET total_count=emp_count;
CLOSE emp_cursor;
END //
DELIMITER ;
CALL get_count_by_limit_total_salary(200000,@total_count);
SELECT @total_count;
- 游标为逐条读取结果集中的数据,提供了完美的解决方案
- 但会对数据进行加锁,并在业务并发量大的时候,不仅会影响业务之间的效率,还会消耗系统资源,造成内存不足