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

存储过程与函数

概念

好处

区别

存储过程

数据准备

创建

语法

示例

调用

语法

示例

查看

语法

示例

删除

语法

示例

存储过程语法

(1)变量

(2)if语句

(3)参数的传递

(4)case语句的使用

(5)while循环

(6)repeat循环

(7)loop循环

游标

存储过程总结

存储函数

语法

创建存储函数

调用存储函数

删除存储函数


存储过程与函数

概念

存储过程和函数是 事先经过编译并存储在数据库中的一段 SQL 语句的集合

好处

  • 存储过程和函数可以重复使用,减轻开发人员的工作量。类似于java中方法可以多次调用

  • 减少网络流量,存储过程和函数位于服务器上,调用的时候只需要传递名称和参数即可

  • 减少数据在数据库和应用服务器之间的传输,可以提高数据处理的效率

  • 将一些业务逻辑在数据库层面来实现,可以减少代码层面的业务处理

类似于Java的方法!即:MySQL可以自己写一个函数,将某一些功能封装起来,Java可以直接调用函数。

区别

  • 函数必须有返回值

  • 存储过程没有返回值

存储过程

数据准备

-- 创建db8数据库
CREATE DATABASE db8;

-- 使用db8数据库
USE db8;

-- 创建学生表
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,	-- 学生id
	NAME VARCHAR(20),					-- 学生姓名
	age INT,							-- 学生年龄
	gender VARCHAR(5),					-- 学生性别
	score INT                           -- 学生成绩
);
-- 添加数据
INSERT INTO student VALUES (NULL,'张三',23,'男',95),(NULL,'李四',24,'男',98),
(NULL,'王五',25,'女',100),(NULL,'赵六',26,'女',90);

-- 按照性别进行分组,查询每组学生的总成绩。按照总成绩的升序排序
SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;

创建

语法

-- 修改分隔符为$
DELIMITER $

-- 标准语法
CREATE PROCEDURE 存储过程名称(参数...)
BEGIN
	sql语句;
END$

-- 修改分隔符为分号
DELIMITER ;

注意上述有新的关键字:delimiter(定界符)、procedure(程序)

示例

-- 修改分隔符为$
DELIMITER $

-- 创建存储过程,封装分组查询学生总成绩的sql语句
CREATE PROCEDURE stu_group()
BEGIN
	SELECT gender,SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;
END$

-- 修改分隔符为分号
DELIMITER ;

执行结束后,观察SQLyog的侧边栏

在存储过程多了一个stu_group

调用

语法

CALL 存储过程名称(实际参数);

就像调用函数一样。

示例

CALL stu_group();

查看

语法

-- 查询数据库中所有的存储过程 标准语法
SELECT * FROM mysql.proc WHERE db='数据库名称';

示例

SELECT * FROM mysql.proc WHERE db='db8';

还可以:

SHOW PROCEDURE STATUS;

删除

语法

DROP PROCEDURE [IF EXISTS] 存储过程名称;

示例

DROP PROCEDURE IF EXISTS stu_group;

存储过程语法

存储过程是可以进行编程的。意味着可以使用变量、表达式、条件控制语句、循环语句等,来完成比较复杂的功能!

(1)变量

定义变量 (declare)

DECLARE 变量名 数据类型 [DEFAULT 默认值];

-- 定义一个int类型变量、并赋默认值为10
DELIMITER $

CREATE PROCEDURE pro_test1()
BEGIN
	DECLARE num INT DEFAULT 10;   -- 定义变量
	SELECT num;                   -- 查询变量
END$

DELIMITER ;


-- 调用pro_test1存储过程
CALL pro_test1();

变量的赋值方法一:

SET 变量名 = 变量值;

-- 定义字符串类型变量,并赋值
DELIMITER $

CREATE PROCEDURE pro_test2()
BEGIN
	DECLARE NAME VARCHAR(10);   -- 定义变量
	SET NAME = '存储过程';       -- 为变量赋值
	SELECT NAME;                -- 查询变量
END$

DELIMITER ;

-- 调用pro_test2存储过程
CALL pro_test2();

  

变量的赋值方法二:

SELECT 列名 INTO 变量名 FROM 表名 [WHERE 条件];

-- 定义两个int变量,用于存储男女同学的总分数
DELIMITER $

CREATE PROCEDURE pro_test3()
BEGIN
	DECLARE men,women INT;  -- 定义变量
   
    -- 计算男同学总分数赋值给men
	SELECT SUM(score) INTO men FROM student WHERE gender='男';
    -- 计算女同学总分数赋值给woman    
	SELECT SUM(score) INTO women FROM student WHERE gender='女'; 
	
    SELECT men,women;           -- 查询变量
END$

DELIMITER ;

-- 调用pro_test3存储过程
CALL pro_test3();

(2)if语句

语法

IF 判断条件1 THEN 执行的sql语句1;
[ELSEIF 判断条件2 THEN 执行的sql语句2;]
...
[ELSE 执行的sql语句n;]
END IF;

示例 

定义一个int变量,用于存储班级总成绩
定义一个varchar变量,用于存储分数描述
根据总成绩判断:
        380分及以上    学习优秀
        320 ~ 380     学习不错
        320以下       学习一般

DELIMITER $

CREATE PROCEDURE pro_test4()
BEGIN
	-- 定义总分数变量
	DECLARE total INT;
	-- 定义分数描述变量
	DECLARE description VARCHAR(10);
	-- 为总分数变量赋值
	SELECT SUM(score) INTO total FROM student;
	-- 判断总分数
	IF total >= 380 THEN 
		SET description = '学习优秀';
	ELSEIF total >= 320 AND total < 380 THEN 
		SET description = '学习不错';
	ELSE 
		SET description = '学习一般';
	END IF;
	
	-- 查询总成绩和描述信息
	SELECT total,description;
END$

DELIMITER ;

-- 调用pro_test4存储过程
CALL pro_test4();

(3)参数的传递

语法

-- 标准语法
CREATE PROCEDURE 存储过程名称([IN OUT INOUT] 参数名 数据类型)
BEGIN
    执行的sql语句;
END$

  • IN:代表输入参数,需要由调用者传递实际数据。默认的
  • OUT:代表输出参数,该参数可以作为返回值
  • INOUT:代表既可以作为输入参数,也可以作为输出参数

示例

输入总成绩变量,代表学生总成绩
输出分数描述变量,代表学生总成绩的描述
根据总成绩判断:
        380分及以上  学习优秀
        320 ~ 380    学习不错
        320以下      学习一般

DELIMITER $

CREATE PROCEDURE pro_test6(IN total INT,OUT description VARCHAR(10))
BEGIN
	-- 判断总分数
	IF total >= 380 THEN 
		SET description = '学习优秀';
	ELSEIF total >= 320 AND total < 380 THEN 
		SET description = '学习不错';
	ELSE 
		SET description = '学习一般';
	END IF;
END$

DELIMITER ;

-- 调用pro_test6存储过程
CALL pro_test6(310,@description);

-- 查询总成绩描述
SELECT @description;

注意:

@变量名:  这种变量要在变量名称前面加上“@”符号,叫做用户会话变量,代表整个会话过程他都是有作用的,这个类似全局变量一样。

@@变量名: 这种在变量前加上 "@@" 符号, 叫做系统变量 

(4)case语句的使用

语法(一)

-- 标准语法
CASE 表达式
WHEN 值1 THEN 执行sql语句1;
[WHEN 值2 THEN 执行sql语句2;]
...
[ELSE 执行sql语句n;]
END CASE;

语法(二)

-- 标准语法
CASE
WHEN 判断条件1 THEN 执行sql语句1;
[WHEN 判断条件2 THEN 执行sql语句2;]
...
[ELSE 执行sql语句n;]
END CASE;

示例

    输入总成绩变量,代表学生总成绩
    定义一个varchar变量,用于存储分数描述
    根据总成绩判断:
        380分及以上  学习优秀
        320 ~ 380    学习不错
        320以下      学习一般 

DELIMITER $

CREATE PROCEDURE pro_test7(IN total INT)
BEGIN
	-- 定义变量
	DECLARE description VARCHAR(10);
	-- 使用case判断
	CASE
	WHEN total >= 380 THEN
		SET description = '学习优秀';
	WHEN total >= 320 AND total < 380 THEN
		SET description = '学习不错';
	ELSE 
		SET description = '学习一般';
	END CASE;
	
	-- 查询分数描述信息
	SELECT description;
END$

DELIMITER ;

-- 调用pro_test7存储过程
CALL pro_test7(390);
CALL pro_test7((SELECT SUM(score) FROM student));

(5)while循环

语法

-- 标准语法
初始化语句;
WHILE 条件判断语句 DO
    循环体语句;
    条件控制语句;
END WHILE;

示例

/*
	计算1~100之间的偶数和
*/
DELIMITER $

CREATE PROCEDURE pro_test8()
BEGIN
	-- 定义求和变量
	DECLARE result INT DEFAULT 0;
	-- 定义初始化变量
	DECLARE num INT DEFAULT 1;
	-- while循环
	WHILE num <= 100 DO
		-- 偶数判断
		IF num%2=0 THEN
			SET result = result + num; -- 累加
		END IF;
		
		-- 让num+1
		SET num = num + 1;         
	END WHILE;
	
	-- 查询求和结果
	SELECT result;
END$

DELIMITER ;

-- 调用pro_test8存储过程
CALL pro_test8();

(6)repeat循环

语法

-- 标准语法
初始化语句;
REPEAT
    循环体语句;
    条件控制语句;
    UNTIL 条件判断语句
END REPEAT;

-- 注意:repeat循环是条件满足则停止。while循环是条件满足则执行

示例

/*
	计算1~10之间的和
*/
DELIMITER $

CREATE PROCEDURE pro_test9()
BEGIN
	-- 定义求和变量
	DECLARE result INT DEFAULT 0;
	-- 定义初始化变量
	DECLARE num INT DEFAULT 1;
	-- repeat循环
	REPEAT
		-- 累加
		SET result = result + num;
		-- 让num+1
		SET num = num + 1;
		
		-- 停止循环
		UNTIL num>10
	END REPEAT;
	
	-- 查询求和结果
	SELECT result;
END$

DELIMITER ;

-- 调用pro_test9存储过程
CALL pro_test9();

(7)loop循环

语法

-- 标准语法
初始化语句;
[循环名称:] LOOP
    条件判断语句
        [LEAVE 循环名称;]
    循环体语句;
    条件控制语句;
END LOOP 循环名称;

注意:

loop可以实现简单的循环,但是退出循环需要使用其他的语句来定义。我们可以使用leave语句完成!
如果不加退出循环的语句,那么就变成了死循环。

/*
	计算1~10之间的和
*/
DELIMITER $

CREATE PROCEDURE pro_test10()
BEGIN
	-- 定义求和变量
	DECLARE result INT DEFAULT 0;
	-- 定义初始化变量
	DECLARE num INT DEFAULT 1;
	-- loop循环
	l:LOOP
		-- 条件成立,停止循环
		IF num > 10 THEN
			LEAVE l;
		END IF;
	
		-- 累加
		SET result = result + num;
		-- 让num+1
		SET num = num + 1;
	END LOOP l;
	
	-- 查询求和结果
	SELECT result;
END$

DELIMITER ;

-- 调用pro_test10存储过程
CALL pro_test10();

游标

概念

  • 游标可以遍历返回的多行结果,每次拿到一整行数据

  • 在存储过程和函数中可以使用游标对结果集进行循环的处理

  • 简单来说游标就类似于集合的迭代器遍历

  • MySQL中的游标只能用在存储过程和函数中

语法

创建游标

DECLARE 游标名称 CURSOR FOR 查询sql语句;

打开游标

OPEN 游标名称;

使用游标获取数据

FETCH 游标名称 INTO 变量名1,变量名2,...;

关闭游标

CLOSE 游标名称;

示例

-- 创建stu_score表
CREATE TABLE stu_score(
	id INT PRIMARY KEY AUTO_INCREMENT,
	score INT
);

/*
	将student表中所有的成绩保存到stu_score表中
*/
DELIMITER $

CREATE PROCEDURE pro_test11()
BEGIN
	-- 定义成绩变量
	DECLARE s_score INT;
	-- 创建游标,查询所有学生成绩数据
	DECLARE stu_result CURSOR FOR SELECT score FROM student;
	
	-- 开启游标
	OPEN stu_result;
	
	-- 使用游标,遍历结果,拿到第1行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第2行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第3行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第4行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 关闭游标
	CLOSE stu_result;
END$

DELIMITER ;

-- 调用pro_test11存储过程
CALL pro_test11();

-- 查询stu_score表
SELECT * FROM stu_score;


-- ===========================================================
/*
	出现的问题:
		student表中一共有4条数据,我们在游标遍历了4次,没有问题!
		但是在游标中多遍历几次呢?就会出现问题
*/
DELIMITER $

CREATE PROCEDURE pro_test11()
BEGIN
	-- 定义成绩变量
	DECLARE s_score INT;
	-- 创建游标,查询所有学生成绩数据
	DECLARE stu_result CURSOR FOR SELECT score FROM student;
	
	-- 开启游标
	OPEN stu_result;
	
	-- 使用游标,遍历结果,拿到第1行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第2行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第3行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第4行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 使用游标,遍历结果,拿到第5行数据
	FETCH stu_result INTO s_score;
	-- 将数据保存到stu_score表中
	INSERT INTO stu_score VALUES (NULL,s_score);
	
	-- 关闭游标
	CLOSE stu_result;
END$

DELIMITER ;

-- 调用pro_test11存储过程
CALL pro_test11();

-- 查询stu_score表,虽然数据正确,但是在执行存储过程时会报错
SELECT * FROM stu_score;

存储过程总结

  • 存储过程是 事先经过编译并存储在数据库中的一段 SQL 语句的集合。可以在数据库层面做一些业务处理

  • 说白了存储过程其实就是将sql语句封装为方法,然后可以调用方法执行sql语句而已

  • 存储过程的好处

    • 安全

    • 高效

    • 复用性强

存储函数

  • 存储函数和存储过程是非常相似的。存储函数可以做的事情,存储过程也可以做到!

  • 存储函数有返回值,存储过程没有返回值(参数的out其实也相当于是返回数据了)

语法

创建存储函数

DELIMITER $

-- 标准语法
CREATE FUNCTION 函数名称([参数 数据类型])
RETURNS 返回值类型
BEGIN
    执行的sql语句;
    RETURN 结果;
END$

DELIMITER ;

调用存储函数

SELECT 函数名称(实际参数);

删除存储函数

DROP FUNCTION 函数名称;

示例

/*
	定义存储函数,获取学生表中成绩大于95分的学生数量
*/
DELIMITER $

CREATE FUNCTION fun_test1()
RETURNS INT
BEGIN
	-- 定义统计变量
	DECLARE result INT;
	-- 查询成绩大于95分的学生数量,给统计变量赋值
	SELECT COUNT(*) INTO result FROM student WHERE score > 95;
	-- 返回统计结果
	RETURN result;
END$

DELIMITER ;

-- 调用fun_test1存储函数
SELECT fun_test1();

posted @ 2022-02-23 02:14  金鳞踏雨  阅读(26)  评论(0编辑  收藏  举报  来源