说明:系统变量由系统提供,不是用户定义,属于服务器层面。系统变量又分为全局变量和会话变量。
必须拥有super权限才能为系统变量赋值,作用域为整个服务器,也就是针对所有连接(会话)有效。
语法:
SHOW GLOBAL VARIABLES;
语法:
SHOW GLOBAL VARIABLES 条件;
案例:
SHOW GLOBAL VARIABLES LIKE '%character%';
语法:
SELECT @@global.系统变量名;
案例:
SELECT @@global.autocommit;
语法:
方式一:
SET GLOBAL 系统变量名=值;
方式二:
SET @@global.系统变量名=值;
案例:
SET GLOBAL autocommit=0;
SET @@global.autocommit=0;
仅仅针对于当前会话(连接)有效。
语法:
SHOW 【SESSION】 VARIABLES;
语法:
SHOW 【SESSION】 VARIABLES 条件;
案例:
SHOW 【SESSION】 VARIABLES LIKE '%character%';
语法:
SELECT @@【session.】系统变量名;
案例:
SELECT @@tx_isolation;
SELECT @@session.tx_isolation;
语法:
方式一:
SET 【SESSION】 系统变量名=值;
方式二:
SET @@【session.】系统变量名=值;
案例:
SET @@session.autocommit=0;
SET @@autocommit=0;
SET SESSION autocommit=0;
SET autocommit=0;
说明:自定义变量是用户自定义的,不是由系统定义的。
针对于当前会话(连接)有效,同于会话变量的作用域。
应用在任何地方,也就是BEGIN END(后面讲)里面或BEGIN END外面
三种
SET @用户变量名=值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
方式一:与声明并初始化一样
SET @用户变量名=值;
SET @用户变量名:=值;
SELECT @用户变量名:=值;
方式二:通过SELECT INTO
SELECT 字段 INTO 变量名
FROM 表;
SELECT @用户变量名;
案例1:
#1.声明并初始化
SET @count=1;
#2.赋值
SELECT COUNT(*) INTO @count
FROM employees;
#3.使用
SELECT @count;
SET @m=1;
SET @n=2;
SET @sum=@m+@n;
SELECT @sum;
仅仅在定义该局部变量的BEGIN END中有效
必须应用在BEGIN END中的第一句话
两种
DECLARE 局部变量名 类型;
DECLARE 局部变量名 类型 DEFAULT 值;
方式一:通过SET或SELECT(三种)
SET 局部变量名=值;
SET 局部变量名:=值;
SELECT @局部变量名:=值;
方式二:通过SELECT INTO
SELECT 字段 INTO 局部变量名
FROM 表;
SELECT 局部变量名;
作用域 | 定义和使用的位置 | 语法 | |
---|---|---|---|
用户变量 | 当前会话 | 会话中的任何地方 | 必须加@符号,不用限定类型 |
局部变量 | BEGIN END中 | 只能在BEGIN END中,且为第一句话 | 一般不用加@符号,需要限定类型 |
类似于Java中的方法,事先经过编译并存储在数据库中的一段SQL语句的集合。
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体 #一组合法的SQL语句
END
BEGIN END就类似于Java中方法体的两个大括号
注意:
IN stuname VARCHAR(20)
DELIMITER
关键字重新设置,并且要写在创建存储过程的语句之前,例如DELIMITER $
,那么整个存储过程的最后要加一个$
,并且之后的结束标记都要用它参数模式:
CALL 存储过程名(实参列表);
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,pwd)
VALUES('john','0000'),('mike','0100'),('lily','1234'),('tom','6666'),('rose','8888');
END $
CALL myp1()$
SELECT * FROM admin$
案例1:假设有boy表和girl表,创建存储过程实现根据女生名,查询对应的男朋友信息
DELIMITER $
CREATE PROCEDURE myp2(IN girlname VARCHAR(20))
BEGIN
SELECT b.*
FROM boy b
RIGHT JOIN girl g ON b.id=g.boyfriend_id#因为有的女生没有男朋友,因此用外连接,女生是主表
WHERE g.gname=girlname;
END $
CALL myp2('小红')$
案例2:假设有如下admin表,创建存储过程,实现检验用户是否登录成功
DELIMITER $
CREATE PROCEDURE myp3(IN username VARCHAR(20),IN pwd VARCHAR(4))
BEGIN
DECLARE result INT DEFAULT 0;
SELECT COUNT(*) INTO result
FROM admin
WHERE admin.username=username
AND admin.pwd=pwd;
SELECT IF(result>0,'成功','失败') 登录;
END $
CALL myp3('mike','0100')$
DELIMITER $
CREATE PROCEDURE myp4(IN girlname VARCHAR(20),OUT boyname VARCHAR(20))
BEGIN
SELECT b.bname INTO boyname
FROM boy b
RIGHT JOIN girl g ON b.id=g.boyfriend_id#因为有的女生没有男朋友,因此用外连接,女生是主表
WHERE g.gname=girlname;
END $
SET @bname$#自定义一个用户变量,用来接收返回值,也可以省略这一步
CALL myp4('小玉',@bname)$
SELECT @bname$
DELIMITER $
CREATE PROCEDURE myp5(IN girlname VARCHAR(20),OUT boyname VARCHAR(20),OUT age INT)
BEGIN
SELECT b.bname,b.age INTO boyname,age
FROM boy b
RIGHT JOIN girl g ON b.id=g.boyfriend_id#因为有的女生没有男朋友,因此用外连接,女生是主表
WHERE g.gname=girlname;
END $
CALL myp5('小敏',@bname,@age)$
SELECT @bname,@age$
案例1:传入a和b两个值,最终a和b都翻倍并返回
DELIMITER $
CREATE PROCEDURE myp6(INOUT a INT,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
SET @a=1$
SET @b=2$
CALL myp6(@a,@b)$
SELECT @a,@b$
语法:
DROP PROCEDURE 存储过程名;
案例:
DROP PROCEDURE myp1;
注意:一条删除存储过程的SQL语句只能删除一个存储过程,不能一次删除多个
语法:
SHOW CREATE PROCEDURE 存储过程名;
案例:
SHOW CREATE PROCEDURE myp1;
练习题1:创建存储过程实现传入一个日期,格式化成xx年xx月xx日并返回
DELIMITER $
CREATE PROCEDURE myp7(IN date1 DATE,OUT str VARCHAR(20))
BEGIN
SELECT DATE_FORMAT(date1,'%y年%m月%d日') INTO str;
END $
CALL myp7(NOW(),@str)$
SELECT @str$
练习题2:创建存储过程实现传入女生名称,返回:“女生名 and 男生名” 格式的字符串
DELIMITER $
CREATE PROCEDURE myp8(IN girlname VARCHAR(20),OUT str VARCHAR(50))
BEGIN
SELECT CONCAT(g.gname,' and ',IFNULL(b.bname,'null')) INTO str
FROM girl g
LEFT JOIN boy b ON b.id=g.boyfriend_id
WHERE g.gname=girlname;
END $
CALL myp8('小婉',@str)$
SELECT @str$
练习题3:创建存储过程,根据传入的起始索引和条目数,查询girl表的记录
DELIMITER $
CREATE PROCEDURE myp9(IN startIndex INT,IN size INT)
BEGIN
SELECT * FROM girl
LIMIT startIndex,size;
END $
CALL myp9(2,2)$
类似于Java中的方法,事先经过编译并存储在数据库中的一段SQL语句的集合。
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1个返回,适合做数据处理后返回一个结果
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
END
注意:
SELECT 函数名(参数列表);
案例:返回公司的员工个数
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0;
SELECT COUNT(*) INTO c
FROM employees;
RETURN c;
END $
SELECT myf1()$
案例1:根据员工名,返回他的工资
DELIMITER $
CREATE FUNCTION myf1(empname VARCHAR(20)) RETURNS DOUBLE
BEGIN
SET @sal=0;
SELECT salary INTO @sal
FROM employees
WHERE last_name=empname;
RETURN @sal;
END $
SELECT myf1('kochhar')$
案例2:根据部门名,返回该部门的平均工资
DELIMITER $
CREATE FUNCTION myf2(depname VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE avg_sal DOUBLE DEFAULT 0;
SELECT AVG(salary) INTO avg_sal
FROM employees e
JOIN departments d ON e.department_id=d.department_id
WHERE d.department_name=depname;
RETURN avg_sal;
END $
SELECT myf2('IT')$
案例3:创建函数,实现传入两个float值,返回两值之和
DELIMITER $
CREATE FUNCTION myf3(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
DECLARE SUM FLOAT DEFAULT 0;
SET SUM=num1+num2;
RETURN SUM;
END $
SELECT myf3(1.33,2.453)$
SHOW CREATE FUNCTION 函数名;
DROP FUNCTION 函数名;
功能:实现简单的双分支,也就是IF-ELSE,可应用于任何地方(BEGIN END中或者BEGIN END外面)
语法:
IF(表达式1,表达式2,表达式3)
如果表达式1成立,则IF函数返回表达式2的值,否则返回表达式3的值。
案例:查询所有员工名,如果有奖金备注“有奖金”,没奖金备注“没奖金”
SELECT last_name,IF(commission_pct IS NOT NULL,'有奖金','没奖金') AS 备注
FROM employees;
语法:
CASE 变量|表达式|字段
WHEN 要判断的值1 THEN 返回的值1
WHEN 要判断的值2 THEN 返回的值2
...
ELSE 要返回的值n
END
案例:查询员工的工资,要求:
部门号=30,新工资为1.1倍
部门号=40,新工资为1.2倍
部门号=50,新工资为1.3倍
其他部门,新工资为原工资
SELECT last_name,department_id,salary AS 原工资,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE salary
END AS 新工资
FROM employees;
语法:
CASE
WHEN 要判断的条件1 THEN 返回的值1
WHEN 要判断的条件2 THEN 返回的值2
...
ELSE 要返回的值n
END
案例:查询员工的工资级别,要求:
如果工资>20000,显示A级别
如果工资>15000,显示B级别
如果工资>10000,显示C级别
否则,显示D级别
SELECT last_name,salary,
CASE
WHEN salary>20000 THEN 'A'
WHEN salary>15000 THEN 'B'
WHEN salary>10000 THEN 'C'
ELSE 'D'
END AS 工资级别
FROM employees;
语法:
CASE 变量|表达式|字段
WHEN 要判断的值1 THEN 语句1;
WHEN 要判断的值2 THEN 语句2;
...
ELSE 语句n;
END CASE;
语法:
CASE
WHEN 要判断的条件1 THEN 语句1;
WHEN 要判断的条件2 THEN 语句2;
...
ELSE 语句n;
END CASE;
案例:创建存储过程,根据传入的成绩,来显示等级,比如传入的成绩:90-100,显示A;80-89,显示B;60-79,显示C;否则,显示D
DELIMITER $
CREATE PROCEDURE myp10(IN score INT)
BEGIN
CASE
WHEN score>=90 AND score<=100 THEN SELECT 'A';
WHEN score>=80 AND score<=89 THEN SELECT 'B';
WHEN score>=60 AND score<=79 THEN SELECT 'C';
ELSE SELECT 'D';
END CASE;
END $
CALL myp10(78)$
功能:实现多重分支,只能应用于BEGIN END中
语法:
IF 条件1 THEN 语句1;
ELSEIF 条件2 THEN 语句2;
...
ELSE 语句n;
END IF;
ELSE也可以省略,如果ELSE省略了,并且所有IF的条件都不满足,则返回NULL
案例:创建函数,根据传入的成绩,来显示等级,比如传入的成绩:90-100,显示A;80-89,显示B;60-79,显示C;否则,显示D
DELIMITER $
CREATE FUNCTION myf4(score INT) RETURNS CHAR
BEGIN
IF score>=90 AND score<=100 THEN RETURN 'A';
ELSEIF score>=80 AND score<=89 THEN RETURN 'B';
ELSEIF score>=70 AND score<=79 THEN RETURN 'C';
ELSE RETURN 'D';
END IF;
END $
SELECT myf4(87)$
CASE结构中,如果WHEN中的值满足或者条件成立,则执行对应的THEN后面的语句,并且结束CASE;如果都不满足,则执行ELSE中的语句或值。ELSE也可以省略,如果ELSE省略了,并且所有WHEN的值或条件都不满足,则返回NULL。
分支结构 | 应用场景 |
---|---|
IF函数 | BEGIN END中或者BEGIN END外面 |
IF结构 | 只能在BEGIN END中 |
CASE作为表达式 | BEGIN END中或者BEGIN END外面 |
CASE作为独立的语句 | 只能在BEGIN END中 |
【标签:】WHILE 循环条件 DO
循环体;
END WHILE 【标签】;
类似于Java中的:
while(循环条件){
循环体;
}
DELIMITER $
CREATE PROCEDURE pro_while1(IN count1 INT)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i<=count1 DO
INSERT INTO admin VALUES(CONCAT('mike',i),'1234');
SET i=i+1;
END WHILE;
END $
CALL pro_while1(5)$
SELECT * FROM admin$
案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次
DELIMITER $
CREATE PROCEDURE pro_while3(IN count1 INT)
BEGIN
DECLARE i INT DEFAULT 0;
a:WHILE i<=count1 DO
SET i=i+1;
IF MOD(i,2)!=0 THEN ITERATE a;
END IF;
INSERT INTO admin VALUES(CONCAT('mike',i),'1234');
END WHILE a;
END $
CALL pro_while3(30)$
SELECT * FROM admin$
/*
int i=0;
while(i<=count1){
i++;
if(i%2!=0){
continue;
}
插入
}
*/
案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
DELIMITER $
CREATE PROCEDURE pro_while2(IN count1 INT)
BEGIN
DECLARE i INT DEFAULT 1;
a:WHILE i<=count1 DO
INSERT INTO admin VALUES(CONCAT('mike',i),'1234');
IF i>=20 THEN LEAVE a;
END IF;
SET i=i+1;
END WHILE a;
END $
CALL pro_while2(25)$
SELECT * FROM admin$
【标签:】LOOP
循环体;
END LOOP 【标签】;
可以用来模拟简单的死循环。
【标签:】REPEAT
循环体;
UNTIL 结束循环的条件
END REPEAT 【标签】;
循环结构 | 特点 | 位置 |
---|---|---|
WHILE | 先判断后执行 | BEGIN END中 |
LOOP | 没有条件的死循环 | BEGIN END中 |
REPEAT | 先执行后判断 | BEGIN END中 |
练习题:已知表stringcontent,其中字段:
id 自增长
content VARCHAR(20)
向该表插入指定个数的,随机位数的由a-z按顺序组成的字符串
DELIMITER $
CREATE PROCEDURE randstr(IN count1 INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';
DECLARE startindex INT DEFAULT 1;
DECLARE len INT DEFAULT 1;
WHILE i<=count1 DO
SET len=FLOOR(RAND()*(26-startindex+1)+1);#产生一个随机的整数,代表截取长度:1-(26-startindex+1)
SET startindex=FLOOR(RAND()*26+1);#产生一个随机的整数,代表起始索引1-26
INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startindex,len));
SET i=i+1;
END WHILE;
END $
CALL randstr(10)$
SELECT * FROM stringcontent$