本文介绍MySQL数据库中的变量、存储过程、函数以及流程控制结构。这一块是MySQL基础中不会频繁涉及的,但一旦使用就会极大提高工作效率的,特别是存储过程
和函数
。
文章目录
一、变量
MySQL中的变量主要分为系统变量和自定义变量,系统变量又分为全局变量和会话变量,自定义变量分为用户变量和局部变量。
(一)系统变量
系统变量是由系统定义
,不是用户定义的,属于服务器层面的变量。在系统变量中,又分为全局变量和会话变量,全局变量需要添加global
关键字,针对于所有会话(连接)有效,但不能跨重启(重启服务器后失效,可通过修改配置文件进行设置);会话变量需要添加session
关键字,针对于当前会话(连接)有效;如果不写标识,默认是会话变量。
系统变量的使用:
- 查看所有系统变量
show global |【session】variables; - 查看满足条件的部分系统变量
show global |【session】 variables like ‘%char%’; - 查看指定的系统变量的值
select @@global. |【session.】系统变量名;
(注意是两个@,如查自动提交变量:select @@global.autocommit; ) - 为某个系统变量赋值
方式一:
set global |【session】系统变量名=值;
(如设置自动提交:set session autocommit = 1;)
方式二:
set @@global. |【session.】系统变量名=值;
(如设置不自动提交:set @@session.autocommit = 0;)
记住上面的使用语法就可以了,下面是对全局变量和会话变量的分别介绍。
1.全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启。
使用:
- 查看所有全局变量
SHOW GLOBAL VARIABLES; - 查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE ‘%char%’; - 查看指定的系统变量的值
SELECT @@global.autocommit;
- 为某个系统变量赋值
方式一:
SET @@global.autocommit=0;
方式二:
SET GLOBAL autocommit=0;
2.会话变量
作用域:针对于当前会话(连接)有效。
使用:
- 查看所有会话变量
SHOW SESSION VARIABLES; - 查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE ‘%char%’; - 查看指定的会话变量的值
SELECT @@session.autocommit;
(其中session.可省略,即等效于SELECT @@autocommit;) - 为某个会话变量赋值
方式一:
SET @@session.autocommit=0;
方式二:
SET SESSION autocommit=0;
(二)自定义变量
自定义变量由用户自定义创建,以满足开发过程的使用。
1.用户变量
用户变量针对于当前会话(连接)有效,作用域同于会话变量。使用时和Java中使用变量一样,分三步:声明、赋值、使用(有查看变量值、比较、运算等)
(1)声明(MySQL中的用户变量声明时必须初始化)。写法如下,必须在变量名前加@符号,支持的赋值符号为=和 :=,但若使用select则必须使用 := 的写法(因为分不清是否为比较运算);声明用户变量不用声明类型。
SET @变量名=值;
(由于等于号会有歧义,如将它与其他值进行比较,因此有下面 :=
的写法)
SET @变量名:=值;
SELECT @变量名:=值;
(2)赋值(或者叫更新变量值)
方式一:
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
方式二:
SELECT 字段 INTO @变量名 FROM 表;
(3)查看变量的值
SELECT @变量名;
案例:用户变量的使用
#声明并赋值
SET @name='john';
SET @name=100;#为变量赋值,修改值,同时修改类型
SET @count=1;
#修改变量的值
SELECT COUNT(*) INTO @count FROM myemployees.employees;
#查看变量的值
SELECT @count;
2.局部变量
局部变量仅仅在定义它的begin end块中有效,并且需要在 begin end中的第一句话开始定义。其使用严格遵循三步走。
(1)声明
DECLARE 变量名 类型 【DEFAULT 值】;
(2)赋值
方式一(与用户变量的赋值相同,也是有三种写法,第三种仍然需要加上@符号):
SET 局部变量名=值;
SET 局部变量名:=值;
SELECT @局部变量名:=值;
方式二:
SELECT 字段 INTO 局部变量名 FROM 表;
(3)查看变量的值
SELECT 局部变量名;
案例1:局部变量的申明与使用
#下面的语句单独执行没有用哦,需要放在begin end中,如案例2的存储过程
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;
案例2:向account表中插入姓名为“Tom”,年龄为用户m(10岁) 和用户n(15岁)之和的一条记录。(涉及到下面的存储过程)
DELIMITER $ #修改sql语句结束的标记为$
CREATE PROCEDURE p1(IN username VARCHAR(20))
BEGIN
DECLARE m INT DEFAULT 10;
DECLARE n INT DEFAULT 15;
DECLARE SUM INT;
SET SUM = m + n;
INSERT INTO account (account.username, age) VALUES (username, SUM);
END $
用户变量和局部变量的对比:
变量类型 | 作用域 | 定义位置 | 语法 |
---|---|---|---|
用户变量 | 当前会话 | 会话的任何地方 | 加@符号,不用指定类型 |
局部变量 | 定义它的BEGIN END中 | BEGIN END的第一句话 | 一般不用加@,需要指定类型 |
二、存储过程
MySQL中的存储过程和函数是相对比较高级的特征,一般的大型的数据库管理系统都具有这样的特征,类似于java中的方法,下面先介绍存储过程。
1.存储过程介绍
含义:存储过程是一组预先编译好的SQL语句的集合,理解成批处理语句。
使用存储过程的好处:
- 提高代码的重用性
- 简化操作
- 减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
创建语法:
DELIMITER 结束标记 #存储过程结尾的符号设置
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(一组合法的SQL语句)
END 结束标记
注意:
1、参数列表包含三部分:(参数模式 参数名 参数类型)
如:CREATE PROCEDURE myp1 (IN stuname VARCHAR(20)) …
参数模式:
in:该参数可以作为输入,也就是该参数需要调用方传入值
out:该参数可以作为输出,也就是该参数可以作为返回值
inout:该参数既可以作为输入又可以作为输出,也就是该参数既可以传入值,又可以返回值
2、如果存储过程体仅仅只有一句话,begin end可以省略
3、存储过程体中的每条sql语句的结尾要求必须加分号。
存储过程的结尾可以使用 delimiter 重新设置,语法为:
delimiter 结束标记,如:delimiter $
调用语法:
CALL 存储过程名(实参列表);
2.存储过程创建案例
案例1(空参列表的存储过程):创建一个存储过程,实现插入到admin表中五条记录。
#创建
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $
#调用
CALL myp1()$
#查看
select * from admin$
案例2(创建带in模式参数的存储过程):创建存储过程实现,根据女神名查询对应的男神信息。
#创建
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name = beautyName;
END $
#调用
CALL myp2('柳岩')$
案例3(创建带两个in模式参数的存储过程):创建存储过程实现,判断用户是否登录成功,即用户名和密码是否匹配。
#创建
CREATE PROCEDURE myp3(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGIN
DECLARE result INT DEFAULT 0;#声明并初始化
SELECT COUNT(*) INTO result#赋值
FROM admin
WHERE admin.username = username
AND admin.password = PASSWORD;
SELECT IF(result>0,'成功','失败') 状态;#使用
END $
#调用
CALL myp3('张飞','8888')$
案例4(创建带out模式参数的存储过程):根据输入的女神名,返回对应的男神名和魅力值
#创建
CREATE PROCEDURE myp4(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT)
BEGIN
SELECT boys.boyname ,boys.usercp INTO boyname,usercp
FROM boys
RIGHT JOIN
beauty b ON b.boyfriend_id = boys.id
WHERE b.name=beautyName ;
END $
#调用
CALL myp4('小昭',@name,@cp)$
SELECT @name,@cp$
案例5(创建带inout模式参数的存储过程):传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp5(INOUT a INT ,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
#调用
SET @m=10$ #需要先定义变量
SET @n=20$
CALL myp5(@m,@n)$
SELECT @m,@n$
3.删除存储过程
语法:drop procedure 存储过程名
存储过程只能一次删除一个,不支持同时删除多个存储过程。
DROP PROCEDURE p1;
DROP PROCEDURE p2,p3;#错误,不支持
4.查看存储过程信息
语法:SHOW CREATE PROCEDURE myp1;
不能使用 DESC myp1;的方式
三、函数
1.函数介绍
含义:函数和存储过程一样,是一组预先编译好的SQL语句的集合,当然就具有以下的特点:
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
函数和存储过程的区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1 个返回,适合做处理数据后返回一个结果
创建语法:
#创建函数的语法注意写的是RETURNS,具体使用查看下面案例
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
END
注意:
1、参数列表包含两部分:参数名 参数类型
2、函数体:肯定会有return语句,如果没有会报错
如果return语句没有放在函数体的最后不报错,但不建议
3、函数体中仅有一句话,则可以省略begin end
4、使用 delimiter语句设置结束标记
调用语法:
SELECT 函数名(参数列表)
2.函数创建案例
案例1(无参有返回):返回公司的员工个数
#创建
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0;#定义局部变量
SELECT COUNT(*) INTO c#赋值
FROM employees;
RETURN c;
END $
#调用
SELECT myf1()$
案例2(有参有返回):根据员工名,返回它的工资
#创建
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
SET @sal=0;#用户变量的作用域为当前会话,放在哪里都行
SELECT salary INTO @sal #赋值
FROM employees
WHERE last_name = empName;
RETURN @sal;
END $
#调用
SELECT myf2('k_ing') $
案例3(有参有返回):根据部门名,返回该部门的平均工资
#创建
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE sal DOUBLE ;
SELECT AVG(salary) INTO sal
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = deptName;
RETURN sal;
END $
#调用
SELECT myf3('IT')$
3.查看函数
语法:SHOW CREATE FUNCTION myf3;
MySQL数据库中的所有存储过程和函数,存在mysql这个数据库的 proc
表中,并且用类型PROCEDURE和FUNCTION加以区别。
4.删除函数
语法:DROP FUNCTION myf3;
四、流程控制结构
mysql中的流程控制结构包括:顺序结构、分支结构与循环结构。
顺序结构:程序从上往下依次执行
分支结构:程序从两条或多条路径中选择一条去执行
循环结构:程序在满足一定条件的基础上,重复执行一段代码
顺序结构很好理解,程序从上往下执行即可,下面主要介绍分支结构和循环结构。
(一)分支结构
1.if函数
功能:实现简单的双分支,类似于java中的if else
语法:if(表达式1, 表达式2, 表达式3)
执行顺序:
如果表达式1成立,则if函数返回表达式2的值,否则返回表达式3的值
应用范围:可以应用在任何地方(如存储过程和函数中,begin end中或外面)
2.case结构
(1)case作为表达式,可以放在begin end中或者begin end外,语法:
情况一:
case 变量|表达式|字段
when 要判断的值 then 返回的值1
when 要判断的值 then 返回的值2
…
else 返回的值n
end
情况二:
case
when 要判断的条件1 then 返回的值1
when 要判断的条件2 then 返回的值2
…
else 返回的值n
end
(2)case作为独立语句,只能放在begin end中,语法:
情况一:
case 变量|表达式|字段
when 要判断的值 then 语句1;
when 要判断的值 then 语句2;
…
else 语句n;
end case;
情况二:
case
when 要判断的条件1 then 语句1;
when 要判断的条件2 then 语句2;
…
else 语句n
end case;
特点:
1.可以作为表达式,嵌套在其他语句中使用,可以放在任何地方,begin end 中或begin end的外面;可以作为独立的语句去使用,只能放在begin end中
2.如果when中的值满足或条件成立,则执行对于功能的then后面的语句,并且结束case
如果都不满足,则执行else中的语句或值
3.else可以省略,如果else省略了,并且所有when条件都不满足,则返回null
案例(case作为独立语句的情况):创建存储过程,根据传入的成绩,来显示等级,如果成绩为90-100,显示A,80-90,显示B,60-80,显示C,否则,显示D
CREATE PROCEDURE test_case (IN score INT)
BEGIN
CASE
WHEN score>=90 AND score<=100 THEN SELECT 'A';
WHEN score>=80 THEN SELECT 'B';
WHEN score>=60 THEN SELECT 'C';
ELSE SELECT 'D';
END CASE;
END $
3.if结构
功能:实现多重分支
语法:
if 条件1 then 语句1;
elseif 条件2 then 语句2; #注意elseif中间没有空格
…
【else 语句n;】
end if;
应用范围:只能应用在begin end 中
案例(使用if结构):创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
CREATE FUNCTION test_if(score INT) RETURNS CHAR
BEGIN
IF score>=90 AND socre<=100 THEN RETURN 'A';
ELSEIF score>=80 THEN RETURN 'B';
ELSEIF score>=60 THEN RETURN 'C';
ELSE RETURN 'D';
END IF;
END $
#当然也可以用case的写法:
CREATE FUNCTION f1(score INT) RETURNS CHAR
BEGIN
DECLARE a CHAR;
CASE
WHEN score>=90 AND score<=100 THEN SET a = 'A';
WHEN score>=80 THEN SET a = 'B';
WHEN score>=60 THEN SET a = 'C';
ELSE SET a = 'D';
END CASE;
RETURN a;
END $
(二)循环结构
介绍:
MySQL中的循环结构分三类:while、loop、repeat
循环控制(即跳转语句):
iterate
类似于 continue,继续,结束本次循环,继续下一次
leave
类似于 break,跳出,结束当前所在的循环
语法:
while:(重点)
【标签:】while 循环条件 do
循环体;
end while【 标签】;
loop:(可以用来模拟简单的死循环)
【标签:】loop
循环体;
end loop 【标签】;
repeat:(类似于do while)
【标签】repeat
循环体;
until 结束循环的条件
end repeat 【标签】;
案例1(while案例):批量插入,根据次数插入到admin表中多条记录
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i<=insertCount DO
INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');#password是关键字,可以加着重号来区别
SET i=i+1;
END WHILE;
END $
案例2(添加leave语句):批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
a:WHILE i<=insertCount DO
INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
IF i>=20 THEN LEAVE a;
END IF;
SET i=i+1;
END WHILE a;
END $
案例3(添加iterate语句):批量插入,根据次数插入到admin表中多条记录,只插入偶数次
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 0;
a:WHILE i<=insertCount DO
SET i=i+1;
IF MOD(i,2)!=0 THEN ITERATE a;
END IF;
INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
END WHILE a;
END $
案例4(流程控制经典案例):创建存储过程,向 stringcontent 表中插入指定个数的随机字符串(长度也随机),该表的结构如下:
CREATE TABLE stringcontent (
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(20)
);
CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';#随机字符串从str字符串中取子串
DECLARE startIndex INT DEFAULT 1;
DECLARE len INT DEFAULT 1;
WHILE i<=insertCount DO
SET len = FLOOR(RAND()*(20-startIndex+1) + 1);#产生一个随机的整数,代表截取长度,1-(26-startIndex+1),此处定义的字符串最大长度为20
SET startIndex=FLOOR(RAND()*26+1);#产生一个随机整数,代表起始索引1-26,RAND()为0~1,RAND()*26为0.X~25.x,加一再向下取整得到1~26
INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));
SET i = i+1;#循环变量更新
END WHILE;
END $