MySQL数据库—存储过程与函数

隐身守侯 提交于 2019-11-28 18:54:46

一、变量

1、系统变量

系统变量由系统提供,属于服务器层面变量,用户不可以声明
可分为全局变量和会话变量

(1)全局变量

全局变量会在mysql启动时赋初始值,无法夸重启使用,如有需要,应该设置配置文件
用法:

#查看所有的全局变量
SHOW GLOBAL VARIABLES;
#查看满足条件的部分全局变量
SHOW GLOBAL VARIABLES LIKE ‘_%;
#查看某个全局变量
SELECT @@GLOBAL.系统变量名;
#为某个全局变量赋值
SET  @@GLOBAL.系统变量名 =;

(2)会话变量

会话变量会在新的连接的赋初始值,作用域为当前连接,无法夸连接使用
用法与全局变量一样,将GLOBAL关键字换为SESSION关键字即可

#查看所有的会话变量
SHOW SESSION VARIABLES;
#查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE ‘_%;
#查看某个会话变量
SELECT @@SESSION.系统变量名;
#为某个会话变量赋值
SET  @@SESSION.系统变量名 =;

2、自定义变量

自定义变量即用户根据某些需求,自己声明并使用的变量
根据作用域不同,可分为用户变量和局部变量

(1)用户变量

用户变量的作用域与会话变量一样,为当前连接有效
使用步骤如下:

#1、声明并初始化:
SET @用户变量名=;
SET @用户变量名:=;
SELECT @用户变量名:=;
#2、赋值:
#方式一:同声明并初始化的语法一样
#方式二:
SELECT 字段 INTO 用户变量名 FROM;
#3、使用用户变量的值:
@用户变量名

(2)局部变量

局部变量的作用域为在一个函数或存储过程中有效
使用步骤如下:

#1、声明:
DECLARE 局部变量名 类型 [DEFAULT]; #类型为sql数据类型中的一个
#2、赋值:
#方法一:
SET 局部变量名=;
SET 局部变量名:=;
SELECT @局部变量名:=;
#方法二:
SELECT 字段 INTO 局部变量名 FROM 表 ….;
SELECT 字段1,字段2... INTO 局部变量1,局部变量2... FROM 表 ….;#同时给多个局部变量赋值

二、存储过程

存储过程是一组预先编译好的sql语句的集合,可理解为批处理语句

1、优点

  • 提高了代码的复用性
  • 简化了操作
  • 减少编译次数,减少了数据库服务器的连接次数,提高了效率

2、存储过程的创建

在存储过程中的sql语句要用分号结尾,为了区分存储过程的结尾,可以自定义一个结尾符号:

DELIMITER $ #定义结尾符号为$

创建一个存储过程的一般写法:

CREATE PROCEDURE 存储过程名(参数模式 参数名 参数类型,参数模式 参数名 参数类型......)
BEGIN
	存储过程体...
END$

参数的参数模式有以下几种:

  • IN:该参数可以作为输入,需要调用方传入值
  • OUT:该参数可以作为输出,可作为返回值
  • INOUT:既可以作为输入也可以作为输出,即需要调用方传入值,又可以返回值

3、存储过程的调用

CALL 存储过程名(参数模式 参数名 参数类型,参数模式 参数名 参数类型......)

4、存储过程的查看

SHOW CREATE PRECEDURE 存储过程名

5、存储过程的删除

DROP PROCEDURE 存储过程名

6、案例

#创建一个user表
CREATE TABLE IF NOT EXISTS user(
	no VARCHAR(20) PRIMARY KEY,
	password VARCHAR(20) NOT NULL
)
  • 创建无参存储过程
      DELIMITER $   #声明结束标记,一个连接只声明一次即可
	#创建
      CREATE PROCEDURE pro1()
      BEGIN
          INSERT INTO user VALUES('1001','123'),('1002','321'),('1003','111');
      END $
      #调用
      CALL pro1()$
  • 创建带IN模式参数的存储过程
	 DELIMITER $   #声明结束标记,一个连接只声明一次即可
	  #传入用户名和密码,显示出是否匹配
      #创建
      CREATE PROCEDURE pro2(IN no VARCHAR(20),IN password VARCHAR(20))
      BEGIN
      		DECLARE result TINYINT DEFAULT 0;
      		SELECT COUNT(1) INTO result
      		FROM user
      		WHERE user.no=no AND user.password=password;
      		SELECT IF(result>0,'true','false');
      END $

		#调用
		CALL pro2(1001’,‘123)$
  • 创建带OUT模式参数的存储过程
	 DELIMITER $   #声明结束标记,一个连接只声明一次即可
      #根据用户名,返回密码
      
      #创建
      CREATE PROCEDURE pro3(IN no VARCHAR(20),OUT password VARCHAR(20))
      BEGIN
      	SELECT user.password INTO password
      	FROM user
      	WHERE user.no = no;
      END $

		#调用
		CALL pro3('1001',@pw)$
		SELECT @pw$
  • 创建带INOUT模式参数的存储过程
 		DELIMITER $   #声明结束标记,一个连接只声明一次即可
		#创建
		CREATE PROCEDURE pro4(INOUT a INT,INOUT b INT)
		BEGIN
			SET a=a*2;
			SET b=b*2;
		END$

		#调用
		SET @m=1$
		SET @n=2$
		CALL pro4(@m,@n)$
		SELECT @m,@n$

三、函数

1、存储过程和函数的比较

存储过程和函数都类似于JAVA的方法
存储过程:可以有0个或多个返回值,适合做批量插入、批量更新
函数:有且只有一个返回值,适合做处理数据后返回一个结果在(类似与自定义的分组函数)

2、函数的创建

CREATE FUNCTION 函数名(参数名 参数类型,参数名 参数类型...) RETURNS 返回类型
BEGIN
		函数体
		RETURN 返回值;(函数体中必须有RETURN语句,建议放在函数体最后)
END

3、函数的调用

SELECT 函数名(参数名 参数类型,参数名 参数类型...) #类似分组函数的使用

4、函数的查看

SHOW CREATE FUNCTION 函数名

5、函数的删除

DROP FUNCTION 函数名

6、案例

  • 无参函数
		DELIMITER $   #声明结束标记,一个连接只声明一次即可
		
       #创建函数 返回user表中人数
		CREATE FUNCTION fun1() RETURNS INT
		BEGIN
			DECLARE c INT DEFAULT 0;
			SELECT COUNT(1) INTO c
			FROM user;
			RETURN c;
		END$

		#调用函数
		SELECT fun1()$
  • 有参函数
		DELIMITER $   #声明结束标记,一个连接只声明一次即可
		
       #创建函数 根据no和password,返回是否匹配
		CREATE FUNCTION fun2(no VARCHAR(20),pw VARCHAR(20)) RETURNS 				VARCHAR(5)
		BEGIN
			DECLARE result TINYINT DEFAULT 0;
			SELECT COUNT(1) INTO result
			FROM user
			WHERE user.no=no AND user.password=pw;
			RETURN IF(result>0,'true','false');
		END$

		#调用函数
		SELECT fun2('1001','123')$

四、流程控制结构

1、顺序结构

2、分支结构

(1)IF结构

IF可以当做一个表达式来用,也可以当做一个语句来用

a.IF作表达式

IF做表达式来用即简单的二分支
可以用在一般的sql语句中,也可以用在存储过程和函数中

SELECT IF(表达式1,表达式2,表达式3);#若满足表达式1,则值为表达式2,否则为表达式3
b.IF作语句

IF做语句来用即多重分支
只可以用在存储过程和函数中,比较常用

IF 条件1 THEN 语句1;
ELSEIF 条件2 THEN 语句2;...
ELSE 语句n;
END IF;

(2)CASE结构

同IF结构一样,CASE也可一当做表达式或独立的语句使用

a.CASE作表达式

CASE作为表达式来用,可以用于一般的sql语句中,也可以用于存储过程和函数中

#方式一
          CASE 变量|表达式|字段
          WHEN1 THEN 返回值1
          WHEN2 THEN 返回值2
          …….
          ELSE 返回值n
          END CASE
#方式二
          CASE 
          WHEN 条件1 THEN 返回值1
          WHEN 条件2 THEN 返回值2
          …….
          ELSE 返回值n
          END CASE
b.CASE作语句

CASE做独立语句来用,只能用在存储过程和函数中

#方式一
          CASE 变量|表达式|字段
          WHEN1 THEN 语句1;
          WHEN2 THEN 语句2;
          …….
          ELSE 语句1;
          END CASE
#方式二
          CASE 
          WHEN 条件1 THEN 语句1;
          WHEN 条件2 THEN 语句2;
          …….
          ELSE 语句n;
          END CASE

3、循环结构

循环结构有以下三种:

  • WHILE:先判断在执行,常用
  • LOOP:没有跳出循环的条件,只能搭配循环控制使用,可以用来模拟简单的死循环
  • REPEAT:先执行再判断,至少执行一次

循环控制有以下两种:

  • ITERATE 结束本次循环,继续下一次
  • LEAVE 结束当前所在的循环

(1)WHILE

[标签:] WHILE 循环条件 DO
			循环体
END WHILE [标签];

(2)LOOP

[标签:] LOOP
		循环体
END LOOP [标签];

(3)REPEAT

[标签:] REPEAT
		循环体
		UNTIL 结束循环的条件
END LOOP [标签];

五、案例

Type 表有type_id(主键)、type_name
book表有book_id(主键)、book_name、book_price、type_id(外键)、book_count
写一个sql脚本,随机插入千万级数据

#建库
CREATE DATABASE books;
USE books;
#建表
CREATE TABLE type(
	type_id INT PRIMARY KEY AUTO_INCREMENT,
	type_name VARCHAR(20) NOT NULL
);
CREATE TABLE book(
	book_id INT PRIMARY KEY AUTO_INCREMENT,
	book_name VARCHAR(20) NOT NULL,
	book_price FLOAT NOT NULL DEFAULT 0,
	type_id INT NOT NULL,
	book_count INT NOT NULL DEFAULT 0,
	CONSTRAINT fk_typeid FOREIGN KEY(type_id) REFERENCES type(type_id) 
);
DELIMITER $ 
SET @base='abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';

#随机字符串函数,输入需要生成的串的长度n
CREATE FUNCTION rand_str(n INT) RETURNS VARCHAR(20)
BEGIN
	DECLARE i INT DEFAULT 0;
	DECLARE tmp VARCHAR(20) DEFAULT '';
	WHILE i<n DO
		SET tmp  =  CONCAT(tmp,SUBSTR(@base,FLOOR(RAND()*52)+1,1));
		SET i = i+1;
	END WHILE;
RETURN tmp;
END$

#生成一个[s,e)的浮点数
CREATE  FUNCTION rand_float(s INT,e INT) RETURNS FLOAT(6,2)
BEGIN
	DECLARE f FLOAT(6,2) DEFAULT 0;
	SET f = ROUND(RAND()*(e-s)+s,2);
	RETURN f;
END$

#生成一个[s,e)的整数
CREATE  FUNCTION rand_int(s INT,e INT) RETURNS INT#[s,e)
BEGIN
	DECLARE i INT DEFAULT 0;
	SET i=FLOOR(RAND()*(e-s)+s);
	RETURN i;
END$

#插入type表数据,n为记录数
CREATE PROCEDURE insert_type(n INT)
BEGIN
	DECLARE i INT DEFAULT 0;
	WHILE i<n DO
	INSERT into type(type_name) VALUES(rand_str(5));
	SET i=i+1;
END WHILE;
END$


#插入book表数据,n为记录数,type_num为type表的记录数(因为有外键)
CREATE PROCEDURE insert_book(n INT,type_num INT)
BEGIN
	DECLARE i INT DEFAULT 0;
	WHILE i<n DO
			INSERT INTO book(book_name,book_price,type_id,book_count) VALUES(rand_str(4),rand_float(0,100),rand_int(1,type_num+1),rand_int(0,10));
			SET i = i+1;
	END WHILE;
END$

CALL insert_type(10)$
CALL insert_book(20,10)$
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!