MySQL笔记(二):存储结构、函数、流程控制

MySQL笔记(二):变量、存储结构、函数、流程控制

变量

MySQL中 的变量分为系统变量和自定义变量,系统变量分为全局变量和会话变量,自定义变量分为局部变量和用户变量

一、系统变量

作用域:

①全局变量作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有的会话(连接)有效,但不能跨重启,如果想重启之后依然生效就要手动修改配置文件

②会话变量作用域:只针对当前会话有效,并且不能跨重启

使用的语法:

①查看所有的系统变量

show global|[session] variables;

②查看满足条件的系统变量

#查看字符集
show global|[session] variables like '%char%';

③查看指定的某个系统变量的值

select @@global|[session].系统变量名;

# 查看当前会话的事务隔离级别
select @@tx_isolation;

④改变系统变量的值

# 方式一:
set global|[session] 系统变量 = 值;

# 方式二:
set @@global|[session].系统变量名 = 值;

注意:如果变量是全局级别,则前面需要加上global;如果是会话级别,则加session,也可以不加,默认就是会话级别

二、自定义变量

(1)用户变量

作用域:针对于当前会话(连接)有效,等同于会话变脸的作用域,可以应用在任何地方(即begin end之内或之位)

应用:

①声明并初始化,声明时必须进行初始化,可以使用SET或SELECT关键字和 =或:=操作符进行声明和初始化操作,SELECT 关键字必须搭配 := 操作符使用

方式一:SET @用户变量名 = 值;

方式二:SET @用户变量名 := 值;

方式一:SELECT @用户变量名 := 值;

②赋值,更新用户变量的值

方式一:通过SET或SELETCT关键字,使用方式和声明时一样

SET @用户变量名 = 值;

SET @用户变量名 := 值;

SELECT @用户变量名 := 值;

方式二:使用SELECT INTO关键字,字段值必须是一个值

SELECT 字段 INTO @变量名 FROM 表;

③使用,使用之前必须先声明

查看用户变量的值:SELECT @用户变量名;

# 声明并初始化用户变量
SET @count = 0;

# 查看用户变量值
SELECT @count;

# 更新用户变量值
SELECT count(*) INTO @count
FROM employees;

(2)局部变量

作用域:仅仅在定义它的begin end中有效

应用:

①声明局部变量

方式一:只声明,不赋值

DECLARE 局部变量名 类型;

方式二:声明并赋值

DEECLARE 局部变量名 类型 DEFAULT 值;

②赋值

方式一:通过SET或SELECT,局部变量名前面不需要加@

SET 局部变量名 = 值;

SET 局部变量名 := 值;

SELECT 局部变量名 := 值;

方式二:通过SELECT INTO,局部变量名前必须加上@

SELECT 字段名 INTO @局部变量名 FROM 表;

③使用

查询变量名

SELECT 局部变量名;

(三)用户变量 PK 局部变量

作用域 定义和使用的位置 语法
用户变量 当前会话 当前会话的任何位置 必须加@符号,声明时不用限定类型
局部变量 仅仅在定义它的begin end中有效 只能在begin end中,且为第一句话 除SELECT INOT外不需要使用@符号,声明时需要限定类型

(4)案例:

# 用户变量
SET @m=1;
SET @n=2;
SET  @sum = @m + @n;
SELECT @sum;
存储过程和函数

存储过程和函数类似于JAVA中的方法

一、存储过程

含义:一组预先编译好的SQL语句的集合,可以理解成批处理语句

优点:①提高代码的重用性

​ ②简化操作

​ ③减少编译次数和数据库的连接次数,提高效率

应用场景:常用于增删改数据,特别是一次性插入大量数据可以大大提高效率

应用:

①创建语法

CREATE PROCEDURE 存储过程名(参数列表)

BEGIN

​ 存储过程体(一组合法的SQL语句)

END

注意事项:

  • 参数列表中包含三部分:参数模式、参数名、参数类型

    IN userId INT
    
  • 参数模式:

    • IN:该参数可以作为输入,也就是说该参数需要调用方在调用时传入值

    • OUT:该参数可以作为输出,也就是说该参数可以作为返回值

    • INOUT:该参数既可以作为输入又可以作为输出,也就是说该参数既需要传入值也可以返回值

    • 如果存储过程体中仅仅只有一句话,BEGIN END可以省略

    • 存储过程体中的每条SQL语句的结尾必须加分号,存储过程的结尾可以使用DELIMITER重新设置

      语法:DELIMITER 结束标记;

      # 以&作为存储过程的结尾符
      DELIMITER &;
      

②调用语法

CALL 存储过程名(实参列表);

案例:

  • 注意:存储过程的命令只能在命令行中执行
# 修改结束标记为 $,后面不要加分号
DELIMITER $

# 案例一:存储过程的参数列表中没有参数
# 第一步:创建存储过程
CREATE PROCEDURE p1()
BEGIN
	INSERT INTO admin(`username`, `password`) VALUES
		('user1', '123456'),
		('user2', '123456'),
		('user3', '123456'),
		('user4', '123456'),
		('user5', '123456'); # sql语句后面必须加上分号,表示该SQL语句的结束
END $

# 第二步:调用存储过程
CALL p1()$

# 案例二:存储过程的参数列表中有IN模式的参数
CREATE PROCEDURE p2(IN username VARCHAR(20), IN password VARCHAR(20))
BEGIN
	# 声明局部变量
	DECLARE count INT DEFAULT 0;
	# 也可以在begin end中声明用户变量
	# SET @sum = 0;
	SELECT count(*) INTO count
	FROM admin as a
	WHERE a.username = username # 参数可以直接使用,如果参数和表的字段名重名,可以在表的字段名前面加上表面进行限定
	AND a.password = password; 
	
	SELECT IF(count > 0,  '登录成功', '登录失败');
END $

CALL p2('user2', '123456')$

# 案例三:存储过程的参数列表中有OUT模式的参数
CREATE PROCEDURE p3(IN userId INT, OUT username VARCHAR(20), OUT password VARCHAR(20))
BEGIN
	# 将a.username的值存储在username变量中,将a.password存储在password变量中
	SELECT a.username, a.password INTO username, password
	FROM admin a
	WHERE a.id = userId;
END $

# 存储过程的实参列表中的用户变量@username和@password可以不进行声明,直接使用
CALL p3(1, @username, @password) $
SELECT @username, @password $

# 将结束标记还原成 ; 
DELIMITER ;

③删除存储过程

语法:DROP PROCEDURE 存储过程名;

④查看存储过程的信息

SHOW CREATE PROCEDURE 存储过程名;

二、函数

函数的含义和优点与存储过程一样

函数与存储过程的区别:存储过程可以有0个返回或多个返回,而函数有且仅有一个返回;存储过程适合做数据的批量插入和批量更新操作,而函数适合做处理数据后返回一个结果

①创建函数

语法:

CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型

BEGIN

​ 函数体

END

注意:

  • 函数的参数列表包含两个部分:参数名和参数类型
  • 函数的函数体中肯定有RETURN语句,如果没有会报错;如果RETURN语句不是放在函数体的最后面也不会报错,但是不建议这么做
  • 如果函数体中只有一条SQL语句,BEGIN END可以省略
  • 也需要使用DELIMITER语句设置结束标记

②调用函数

语法:SELECT 函数名(参数列表);

③查看函数信息

语法:SHOW CREATE FUNCTION 函数名;

④删除函数

语法:DROP FUNCTION 函数名;

案例:

DELIMITER $

# 案例一:无参数
CREATE FUNCTION f1() RETURNS INT
BEGIN
	DECLARE count INT DEFAULT 0;
	SELECT COUNT(*) INTO count FROM admin;
	return count;
END $

SELECT f1() $

# 案例二:有参数
CREATE FUNCTION f2(num1 FLOAT, num2 FLOAT) RETURNS FLOAT
BEGIN
	DECLARE sum FLOAT DEFAULT 0;
	SET sum = num1 + num2;
	RETURN sum;
END $
 
SELECT f2(1.0, 2.5);

DELIMITER ;
流程控制结构

流程控制结构分为:顺序结构、分支结构和循环结构

一、分支结构

(1)、IF函数

①功能:实现简单双分支

②作用域:可以作为表达式放在任何位置,即可以在begin end内和begin end外使用

③语法:

IF (条件表达式, 值1, 值2)

当条件表达式成立时返回值1,否则返回值2

④应用:

select IF(10>5, '10>5成立', '10>5不成立');

(2)、case结构

①功能:实现多分支

②作用域:可以放在任何位置。如果放在begin end 外面,作为表达式结合着其他语句使用;如果放在begin end 里面,一般作为独立的语句使用

③语法:

语法1:类似于switch
case 表达式或字段
​ when 值1 then 语句1;
​ when 值2 then 语句2;
​ …
​ else 语句n;
end;

语法2:
case
​ when 条件1 then 语句1;
​ when 条件2 then 语句2;
​ …
​ else 语句n;
end [case];

④应用:

# 在begin end 外面
SELECT 
	employee_id, last_name, salary,
	CASE salary
		WHEN salary>30000 then 'A级'
		WHEN salary>25000 THEN 'B级'
		WHEN salary>20000 THEN 'C级'
		WHEN salary>15000 THEN 'D级'
		WHEN salary>10000 THEN 'E级'
		ELSE 'F级'
	END as 'level'
FROM
	employees

# 在begin end 里面
CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
BEGIN 
	DECLARE ch CHAR DEFAULT 'A';
	
	CASE 
      WHEN score>90 THEN SET ch='A';
      WHEN score>80 THEN SET ch='B';
      WHEN score>60 THEN SET ch='C';
      ELSE SET ch='D';
	END CASE;
	
	RETURN ch;
END $

(3)、IF结构

①功能:类似于多重if

②作用域:只能应用在begin end 中

③语法:

if 条件1 then

​ 语句1;
elseif 条件2 then

​ 语句2;

else

​ 语句n;
end if;

④应用:

CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
	DECLARE ch CHAR DEFAULT 'A';
	IF score>90 THEN SET ch='A';
	ELSEIF score>80 THEN SET ch='B';
	ELSEIF score>60 THEN SET ch='C';
	ELSE SET ch='D';
	END IF;
	RETURN ch;
END $
二、循环结构

流程控制

分类:iterate、leave

功能:

①iterate类似于 continue,继续,结束本次循环,继续下一次

② leave 类似于 break,跳出,结束当前所在的循环

循环结构

(一)while结构

①语法:标签可以省略,当需要使用到循环控制时,前面的标签才会用到

[标签:]while 循环条件 do

循环体;

end while [标签];

⑥应用:

# 向admin表中添加insertCount条数据
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');
		SET i=i+1;
	END WHILE;
END $

(二)、loop

①功能:一般用来模拟死循环

②语法:

[标签:] loop

循环体;

end loop [标签];

(三)repeat

①功能:相当于do …while,但是until中的条件是结束循环的条件

②语法:

[标签:] repeat

循环体;

until 结束循环的条件
end repeat [标签];

综合案例

场景:admin表中只有三个字段,分别是id(自增主键)、username、password,要求向admin表中添加指定数量的数据,username字段和password字段的值随机生成,并且长度可以指定

源码:

DELIMITER $

DROP FUNCTION IF EXISTS generate_str_random;
/**
*功能:创建一个函数,生成指定长度的随机字符串
*参数:
*type是生成的字符串类型,分别为username和password,两种类型使用的字符库不同,username类型生成的随机字  *符串中只有字母,password类型生成的随机字符串中只有数字
*len是生成的随机字符串的长度
**/
CREATE FUNCTION generate_str_random(type VARCHAR(20), len INT) RETURNS VARCHAR(26) 
BEGIN
	# 存储生成的随机字符串
	DECLARE str VARCHAR(20) DEFAULT '';
	# 生成用户名的字符库
	DECLARE str1 VARCHAR(54) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	# 生成密码的字符库
	DECLARE str2 VARCHAR(10) DEFAULT '0123456789';
	# 记录循环次数
	DECLARE i INT DEFAULT 0;
	# 存储每次随机得到的字符
	DECLARE s CHAR DEFAULT '';
	# 存储随机生成的数字
	DECLARE num INT DEFAULT 1;

	IF type='username' THEN # 生成用户名的随机字符串
		# 循环,每次随机获取一个字符,将得到的字符加入带字符串中
		WHILE i<len DO
			# 生成一个随机数,范围为1到字符库的长度,向上取整
			SET num = CEIL(RAND() * LENGTH(str1));
			# 从字符库的num位置截取一个字符
			SET s = SUBSTR(str1, num, 1);
			# 将随机生产的字符拼接到str中
			SET str = CONCAT(str, s);
			SET i = i+1;
		END WHILE;
	ELSEIF type='password' THEN # 生成密码的随机字符串
		# 循环,每次随机获取一个字符,将得到的字符加入带字符串中
		WHILE i<len DO
			# 生成一个随机数,范围为1到字符库的长度,向上取整
			SET num = CEIL(RAND() * LENGTH(str2));
			# 从字符库的num位置截取一个字符
			SET s = SUBSTR(str2, num, 1);
			# 将随机生产的字符拼接到str中
			SET str = CONCAT(str, s);
			SET i = i+1;
		END WHILE;
	ELSE
		SET str = '';
	END IF;
	
	return str;
END $

DROP PROCEDURE IF EXISTS insert_admin_user;
/**
*功能:创建一个存储过程,用于向admin表中新增指定数量的用户,用户名和密码随机生成
*参数:
*num用于指定插入的数据量
**/
CREATE PROCEDURE insert_admin_user(IN num INT)
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE len INT DEFAULT 6;
  # 循环向admin表中加入数据
  WHILE i < num DO
  	INSERT INTO admin(`username`, `password`) values(generate_str_random('username', len), generate_str_random('password', len));
    SET i = i+1;
  END WHILE;
END $

# 调用存储过程,向admin表中插入1000条数据
CALL insert_admin_user(1000) $

DELIMITER ;

猜你喜欢

转载自blog.csdn.net/hsg_happyLearning/article/details/85998539