MySQL—存储过程详解

news2024/9/25 7:03:29

基本介绍

存储过程和函数是数据库中预先编译并存储的一组SQL语句集合。它们的主要目的是提高代码的复用性、减少数据传输、简化业务逻辑处理,并且一旦编译成功,可以永久有效。

存储过程和函数的好处

  • 提高代码的复用性:存储过程和函数可以在多个地方重复使用,减少了代码的冗余。
  • 减少数据传输:通过在数据库服务器上执行逻辑操作,减少了数据在数据库和应用服务器之间的传输,提高了传输效率。
  • 减少代码层面的业务处理:将复杂的业务逻辑封装在存储过程或函数中,简化了应用层的代码。
  • 一次编译永久有效:存储过程和函数一旦编译成功,可以在数据库中永久使用,无需每次执行时重新编译。

存储过程和函数的区别

  • 存储函数:必须有返回值。存储函数通常用于执行一些计算或转换操作,并返回一个结果。
  • 存储过程:可以没有返回值。存储过程通常用于执行一系列操作,如插入、更新、删除等,不一定需要返回结果。

基本操作

DELIMITER

  • DELIMITER 关键字:用于声明 SQL 语句的分隔符,告诉 MySQL 该段命令已经结束。
  • 默认分隔符:MySQL 语句的默认分隔符是分号 ;。
  • 修改分隔符:当需要在一条功能 SQL 语句中包含分号,但不作为结束标识时,可以使用 DELIMITER 来指定新的分隔符。
DELIMITER 分隔符

存储过程的创建、调用、查看和删除

创建存储过程:

-- 修改分隔符为$
DELIMITER $

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

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

调用存储过程:

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

查看存储过程(MySQL 8.0 及以上版本):

SHOW PROCEDURE STATUS WHERE db='数据库名称';

删除存储过程:

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

数据练习

-- 数据准备
CREATE TABLE student (
    id INT PRIMARY KEY,
    NAME VARCHAR(50),
    age INT,
    gender CHAR(1),
    score INT
);

INSERT INTO student (id, NAME, age, gender, score) VALUES
(1, '张三', 23, '男', 95),
(2, '李四', 24, '男', 98),
(3, '王五', 25, '女', 100),
(4, '赵六', 26, '女', 90);

-- 创建存储过程
DELIMITER $

CREATE PROCEDURE stu_group()
BEGIN
	SELECT gender, SUM(score) getSum FROM student GROUP BY gender ORDER BY getSum ASC;
END$

DELIMITER ;

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

-- 查看存储过程
SHOW PROCEDURE STATUS WHERE Db = 'test';

-- 删除存储过程
DROP PROCEDURE IF EXISTS stu_group;

存储过程语法

变量使用

在存储过程中,可以使用变量来存储和操作数据。变量可以是局部的,也可以是全局的。局部变量只能在 BEGIN ... END 块中使用。

定义变量:

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

变量赋值:

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

示例:

DELIMITER $
CREATE PROCEDURE pro_test3()
BEGIN
	-- 定义两个变量
	DECLARE men, women INT;
	-- 查询男同学的总分数,为men赋值
	SELECT SUM(score) INTO men FROM student WHERE gender='男';
	-- 查询女同学的总分数,为women赋值
	SELECT SUM(score) INTO women FROM student WHERE gender='女';
	-- 使用变量
	SELECT men, women;
END$
DELIMITER ;
-- 调用存储过程
CALL pro_test3();

IF 语句

IF 语句用于条件判断。

语法:

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

示例: 

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 description;
END$
DELIMITER ;
-- 调用pro_test4存储过程
CALL pro_test4();

参数传递

存储过程可以接受参数,参数可以是输入参数、输出参数或输入输出参数。

语法:

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

示例:

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);
CALL pro_test6((SELECT SUM(score) FROM student), @description);
-- 查询总成绩描述
SELECT @description;

查看参数方法

  • @变量名 : 用户会话变量,代表整个会话过程他都是有作用的,类似于全局变量
  • @@变量名 : 系统变量

CASE 语句

CASE 语句用于多条件判断。

语法:

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

示例:

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));

WHILE 循环

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;
		SET num = num + 1;
	END WHILE;
	-- 查询求和结果
	SELECT result;
END$
DELIMITER ;
-- 调用pro_test8存储过程
CALL pro_test8();

REPEAT 循环

REPEAT 循环用于在条件为真之前重复执行代码块。

语法:

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

示例:

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();

LOOP 循环

LOOP 循环用于无条件循环,直到使用 LEAVE 语句退出循环。

语法:

[循环名称:] LOOP
	条件判断语句
		[LEAVE 循环名称;]
	循环体语句;
	条件控制语句;
END LOOP 循环名称;

示例:

计算 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语句;

-- 打开游标,执行对应的SQL查询
OPEN 游标名称;

-- 从游标中提取一行数据到变量中,这些变量用于存储该行的数据
FETCH 游标名称 INTO 变量名1,变量名2,...;

-- 关闭游标,释放其占用的资源
CLOSE 游标名称;

Mysql 通过一个 Error handler 声明来判断指针是否到尾部,并且必须和创建游标的 SQL 语句声明在一起:

DECLARE EXIT HANDLER FOR NOT FOUND (do some action,一般是设置标志变量)

示例:

-- 创建一个名为stu_score的表,用于存储学生成绩
-- 该表包含两个字段:id(自增主键)和score(成绩)
CREATE TABLE stu_score (
    id INT PRIMARY KEY AUTO_INCREMENT,
    score INT
);

-- 改变结束符为$,以便在存储过程中有更多的灵活性
DELIMITER $
-- 创建一个名为pro_test12的存储过程
CREATE PROCEDURE pro_test12()
BEGIN
    -- 定义一个变量s_score,用于存储学生的成绩
    DECLARE s_score INT;
    -- 定义一个变量flag,用于标记游标数据是否结束,默认为0
    DECLARE flag INT DEFAULT 0;
    -- 创建一个游标stu_result,用于获取所有学生表中的成绩数据
    DECLARE stu_result CURSOR FOR SELECT score FROM student;
    -- 当游标数据结束后,将flag设置为1,用于控制重复循环的结束
    DECLARE EXIT HANDLER FOR NOT FOUND SET flag = 1;
    -- 打开游标stu_result,准备获取数据
    OPEN stu_result;
    -- 重复执行以下语句,直到游标数据结束
    REPEAT
        -- 使用FETCH从游标中获取数据,并存储到s_score变量中
        FETCH stu_result INTO s_score;
        -- 将获取的成绩数据插入到stu_score表中
        INSERT INTO stu_score VALUES (NULL, s_score);
    -- 当flag等于1时结束循环,即游标数据已全部处理完毕
    UNTIL flag = 1
    END REPEAT;
    -- 关闭游标stu_result,释放资源
    CLOSE stu_result;
END$
-- 恢复结束符为默认的分号
DELIMITER ;

-- 调用pro_test12存储过程,执行存储过程中的逻辑
CALL pro_test12();
-- 查询stu_score表中的所有数据,以验证存储过程的结果
SELECT * FROM stu_score;

存储函数

存储函数和存储过程非常相似,但存储函数有返回值,而存储过程没有返回值(尽管存储过程可以通过 OUT 参数返回数据)。

创建存储函数

语法:

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

当在 MySQL 中创建存储函数时,如果遇到 [HY000][1418] This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled 错误,这是因为 MySQL 的二进制日志(binary logging)默认要求存储函数必须是确定性的(DETERMINISTIC)、不执行 SQL 语句(NO SQL)或只读取 SQL 数据(READS SQL DATA)。

解决方案

  • 可以在存储函数的声明中添加 DETERMINISTIC、NO SQL 或 READS SQL DATA 关键字。 

示例:

定义一个存储函数 fun_test,获取学生表中成绩大于 95 分的学生数量。

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

调用存储函数

由于存储函数有返回值,所以使用 SELECT 调用:

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

删除存储函数

DROP FUNCTION 函数名称;

完整代码 

-- 数据准备
CREATE TABLE student (
    id INT PRIMARY KEY,
    NAME VARCHAR(50),
    age INT,
    gender CHAR(1),
    score INT
);

INSERT INTO student (id, NAME, age, gender, score) VALUES
(1, '张三', 23, '男', 95),
(2, '李四', 24, '男', 98),
(3, '王五', 25, '女', 100),
(4, '赵六', 26, '女', 90);

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

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

-- 删除存储函数
DROP FUNCTION fun_test;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2162857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【NPL】daydayup基本概念,词嵌入

NLP基础 基本概念 NLP&#xff0c;自然语言处理&#xff0c;目标是让计算机能够理解、解释、生成人类语言的数据。包括语言理解&#xff0c;语言生成&#xff0c;机器翻译&#xff0c;情感分享&#xff0c;语音识别&#xff0c;语音合成等 应用方向 自然语言理解 情感分析&a…

Python办公自动化案例:实现XMind文件转换成Excel文件

案例:实现XMind文件转换成Excel文件 将XMind文件转换为Excel文件的过程可以通过几个步骤来实现,主要涉及到读取XMind文件,解析其内容,然后创建一个Excel文件并将解析的内容写入。以下是一个简化的Python脚本,展示了如何使用xmindparser库来解析XMind文件,并使用pandas库…

搜索引擎简介

搜索引擎架构 整个搜索引擎分为三个系统 爬虫系统 索引系统 线上搜素服务 爬虫系统 爬虫分为两个阶段&#xff1a; 第一阶段&#xff1a;根据目标网站的列表页&#xff0c;爬对应的文档 URL 第二阶段&#xff1a;根据文档 URL&#xff0c;下载文档内容 触发器&#xff1…

多级目录SQL分层查询

需求&#xff1a;有多级目录&#xff0c;而目录的层级是不固定的&#xff0c;如下图所示&#xff1a; 数据结构&#xff1a; sql语句&#xff1a; <select id"getList" resultType"com.hikvision.idatafusion.dhidata.bean.vo.knowledgebase.KnowledgeBaseT…

基于SSM的“银发在线教育云平台”的设计与实现(源码+数据库+文档)

基于SSM的“银发在线教育云平台”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 首页页面图 健身养生详情页面 在线课堂界面 …

C++ | Leetcode C++题解之第434题字符串中的单词数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countSegments(string s) {int segmentCount 0;for (int i 0; i < s.size(); i) {if ((i 0 || s[i - 1] ) && s[i] ! ) {segmentCount;}}return segmentCount;} };

一种单目标A*算法设计与实现

一种单目标A*算法设计与实现 作者&#xff1a;吴屏珊 最近在学习简单的单目标A*算法&#xff0c;其中在CSDN上阅读到的一篇博文给了我很大启发&#xff0c;于是在该博文的基础上&#xff0c;笔者记录了一点自己对于A*算法的体会和感悟。原文链接 目录 文章目录 一种单目标A*…

如何破解西门子博途V19里的密码设置

现在使用TIA Portal V19的工程师是越来越多了&#xff0c;V19有个显著的变化就是访问密码的设置&#xff0c;很多小伙伴忽然发现已经用了很多年的功能&#xff0c;在改动以后都不会设置了&#xff0c;那我们今天就带着您看一下如何才能在 V19 中正确的设置 S7-1500 访问密码。 …

论文笔记(四十六)RobotGPT: Robot Manipulation Learning From ChatGPT

xx RobotGPT: Robot Manipulation Learning From ChatGPT 文章概括摘要I. 介绍II. 相关工作III. 方法论A. ChatGPT 提示机器人操作B. 机器人学习 IV. 实验A. 衡量标准B. 实验设置C. 模拟实验D. 真实机器人实验E. AB测试 V. 结论 文章概括 引用&#xff1a; article{jin2024r…

【算法】模拟:(leetcode)6.Z 字形变换(medium)

目录 题目链接 题目介绍 解法 1、模拟&#xff1a; 2、找矩阵中的规律&#xff1a; 公差 第一行和最后一行 中间行 代码 题目链接 6. Z 字形变换 - 力扣&#xff08;LeetCode&#xff09; 题目介绍 解法 1、模拟&#xff1a; 采用模拟的思想&#xff0c;按照Z字形&…

《动手学深度学习》笔记1.7——模型选择 + 过拟合-欠拟合

目录 1. 模型选择 1.1 训练误差 vs. 泛化误差 1.2 验证数据集 vs. 测试数据集 1.3 K-折交叉验证 1.4 总结 2. 过拟合与欠拟合&#xff08;核心知识&#xff09; 2.1 过拟合 vs. 欠拟合 2.2 模型容量 2.3 估计模型容量 2.4 VC维 衡量模型容量 2.5 数据复杂度 3. 代…

Vue3:element-plus el-Table列表合计处理显示字符串类型/计算合计数值

需求整理 1.使用element组件库中的 el-table组件实现图上 底部当前页合计的功能。在一般的情况下&#xff0c;只需要计算数值部分的值&#xff0c;因为组件中的方法中处理的就是将值的类型转换成数值类型&#xff0c;像string类型的字符串的话&#xff0c;在进行转换的时候会出…

什么是远程过程调用(RPC)

进程间通信(IPC) 进程间通信(Inter-Process Communication)是指两个进程或者线程之间传送数据或者信号的一些技术或者方法。进程是计算机进行资源分配的最小的单位。每个进程都有自己独立的系统资源,而且彼此之间是相对隔离的。为了使得不同的进程之间能够互相访问,相互协…

Redis: 特色,业务场景举例,底层原理,持续进阶等问题梳理

Redis 的特色 Redis 是目前使用非常广泛的中间件&#xff0c;在于它功能强大&#xff0c;持续改进&#xff0c;经久不衰主要体现在以下几点 1 ) 高性能: Redis 的底层是C语言编写的&#xff0c;它的定位是内存型数据库而且 Redis 的作者对操作系统也非常的精通它通讯方式采用了…

MobileNetV2: Inverted Residuals and Linear Bottlenecks

Link&#xff1a;https://arxiv.org/abs/1801.04381 这篇文章是一篇关于MobileNetV2的学术论文&#xff0c;主要介绍了MobileNetV2的架构设计及其在图像分类、目标检测和语义分割任务中的应用。以下是对这些核心内容的简要概述&#xff1a; MobileNetV2架构设计&#xff1a; …

深度学习技术在超材料科学中的应用与实操

人工智能算法赋能材料设计与应用专题培训 前沿背景 人工智能与材料科学的融合趋势&#xff1a;在材料科学领域&#xff0c;人工智能&#xff08;AI&#xff09;的引入正在引发一场革命。传统的材料设计和优化依赖于经验和试错方法&#xff0c;这不仅耗时且成本高昂。关于AI赋…

Note_XML学习笔记

XML学习笔记 1. XML 教程 经常见到XML学习一下。由于是学到中间才想起记笔记&#xff0c;之前的就简略回顾一下&#xff1a; 1&#xff09;XML是数据存储的一种语言载体&#xff1b; 2&#xff09;只负责存储&#xff0c;不负责显示&#xff1b; 3&#xff09;和HTML语言的风…

简单的算法题

1、求12345 #include <stdio.h> int main(){int i,s1;for(i1;i<5;i){s s*i;}printf("%d",s); }2、求1357911 #include <stdio.h> int main(){int i,s1;for(i1;i<11;ii2){s s*i;}printf("%d",s); }3、判定2000—2500年中的每一年是否…

CSP-CCF★★★201909-2小明种苹果(续)★★★

一、问题描述 二、解答 关键&#xff1a;判断是否发生苹果掉落&#xff0c;使用flag[]数组来标记&#xff0c;1为掉落&#xff0c;0为没有掉落&#xff0c;这样也是为了后续比较连续三棵树是否掉落 误区&#xff1a;用最后一次正数&#xff08;即最后一次统计苹果个数&#x…

ChatGPT 提取文档内容,高效制作PPT、论文

随着人工智能生成内容&#xff08;AIGC&#xff09;的快速发展&#xff0c;利用先进的技术工具如 ChatGPT 的 RAG&#xff08;Retrieval-Augmented Generation&#xff0c;检索增强生成&#xff09;模式&#xff0c;可以显著提升文档内容提取和内容创作的效率。以下将详细介绍如…