MySQL—存储过程详解
基本介绍
存储过程和函数是数据库中预先编译并存储的一组SQL语句集合。它们的主要目的是提高代码的复用性、减少数据传输、简化业务逻辑处理,并且一旦编译成功,可以永久有效。
存储过程和函数的好处
- 提高代码的复用性:存储过程和函数可以在多个地方重复使用,减少了代码的冗余。
- 减少数据传输:通过在数据库服务器上执行逻辑操作,减少了数据在数据库和应用服务器之间的传输,提高了传输效率。
- 减少代码层面的业务处理:将复杂的业务逻辑封装在存储过程或函数中,简化了应用层的代码。
- 一次编译永久有效:存储过程和函数一旦编译成功,可以在数据库中永久使用,无需每次执行时重新编译。
存储过程和函数的区别
- 存储函数:必须有返回值。存储函数通常用于执行一些计算或转换操作,并返回一个结果。
- 存储过程:可以没有返回值。存储过程通常用于执行一系列操作,如插入、更新、删除等,不一定需要返回结果。
基本操作
DELIMITER
- DELIMITER 关键字:用于声明 SQL 语句的分隔符,告诉 MySQL 该段命令已经结束。
- 默认分隔符:MySQL 语句的默认分隔符是分号 ;。
- 修改分隔符:当需要在一条功能 SQL 语句中包含分号,但不作为结束标识时,可以使用 DELIMITER 来指定新的分隔符。
DELIMITER 分隔符
存储过程的创建、调用、查看和删除
创建存储过程:
-- 修改分隔符为$
DELIMITER $-- 标准语法
CREATE PROCEDURE 存储过程名称(参数...)
BEGINsql语句;
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()
BEGINSELECT 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()
BEGINDECLARE total INT; -- 定义总分数变量DECLARE description VARCHAR(10); -- 定义分数描述变量SELECT SUM(score) INTO total FROM student; -- 为总分数变量赋值-- 判断总分数IF total >= 380 THENSET description = '学习优秀';ELSEIF total >= 320 AND total < 380 THENSET description = '学习良好';ELSESET 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判断CASEWHEN total >= 380 THENSET description = '学习优秀';WHEN total >= 320 AND total < 380 THENSET 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 DOIF num % 2 = 0 THENSET 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+1SET num = num + 1;-- 停止循环UNTIL num > 10END 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 THENLEAVE l;END IF;-- 累加SET result = result + num;-- 让num+1SET 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,用于标记游标数据是否结束,默认为0DECLARE 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 = 1END 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;
相关文章:

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

2024ICPC网络赛2记录:CK
这一次网络赛我们过8题,排名71,算是发挥的非常好的了。这一把我们三个人手感都很好,前六题都是一遍过,然后我又切掉了非签到的E和C,最后时间不是很多,K只想到大概字典树的思路,细节不是很懂就直…...

PerparedStatement概述
PreparedStatement 是 Java 中的一个接口,用于预编译 SQL 语句并执行数据库操作。 一、主要作用 提高性能: 数据库在首次执行预编译语句时会进行语法分析、优化等操作,并将其存储在缓存中。后续执行相同的预编译语句时,数据库可…...

联影医疗嵌入式面试题及参考答案(3万字长文)
假如你要做机器人控制,你会遵循怎样的开发流程? 首先,需求分析阶段。明确机器人的功能需求,例如是用于工业生产中的物料搬运、还是家庭服务中的清洁打扫等。了解工作环境的特点,包括空间大小、障碍物分布、温度湿度等因素。同时,确定机器人的性能指标,如运动速度、精度、…...

Rust的作用?
在Linux中,Rust可以开发命令行工具,如FD、SD、Ripgep、Bat、EXA、SKIM等。虽然Rust是面向系统编程,但也不妨碍使用Rust写命令行工具,因为Rust具备现代语言特性、无依赖、生成的目标文件小。 在云计算和区块链区域,Rus…...

无人机之可承受风速的影响因素
无人机可承受风速的影响因素是多方面的,这些因素共同决定了无人机在特定风速条件下的飞行稳定性和安全性。以下是一些主要的影响因素: 一、无人机设计与结构 无人机的大小、形状和重量都会直接影响其抗风能力。大型无人机由于具有更大的表面积和质量&am…...

HTML与JavaScript结合实现简易计算器
目录 背景: 过程: 代码: HTML部分解析: body部分解析: JavaScript部分解析: 效果图 : 总结: 背景: 计算器是一个典型的HTML和javaScript结合使用的例子,它展示了如何使用H…...

Docker网络原理
Docker 网络是 Docker 容器之间以及容器与外部世界之间通信的机制。Docker 提供了多种网络驱动,允许容器以不同的方式进行通信: Docker 网络工作原理: 网络命名空间:Docker 使用 Linux 的网络命名空间来隔离容器的网络堆栈。每个…...

PyTorch 目标检测教程
PyTorch 目标检测教程 本教程将介绍如何在 PyTorch 中使用几种常见的目标检测模型,包括 Faster R-CNN、SSD 以及 YOLO (You Only Look Once)。我们将涵盖预训练模型的使用、推理、微调,以及自定义数据集上的训练。 1. 目标检测概述 目标检测任务不仅要…...

校园美食导航:Spring Boot技术的美食发现之旅
第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面,分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…...

51单片机 - DS18B20实验1-读取温度
上来一张图,明确思路,程序整体裤架如下,通过单总线,单独封装一个.c文件用于单总线的操作,其实,我们可以把点c文件看成一个类操作,其属性就是我们面向对象的函数,也叫方法,…...

go语言基础入门(一)
变量声明:批量声明变量:变量赋值: 声明变量同时为变量赋值可以在变量声明时为其赋值go中赋值时的编译器会自动根据等号右侧的数据类型自动推导变量的类型使用 : 进行赋值匿名变量 常量常量计数器iota1. 使用场景2. 基本用法3. 简化语法4. 自定义增量5. 复杂使用go的类似枚举 使…...

linux 基础(一)mkdir、ls、vi、ifconfig
1、linux简介 linux是一个操作系统(os: operating system) 中国有没有自己的操作系统(华为鸿蒙HarmonyOS,阿里龙蜥(Anolis) OS 8、百度DuerOS都有) 计算机组的组成:硬件软件 硬件:运算器&am…...

DAMODEL丹摩智算:LLama3.1部署与使用
文章目录 前言 一、LLaMA 3.1 的特点 二、LLaMA3.1的优势 三、LLaMA3.1部署流程 (一)创建实例 (二)通过JupyterLab登录实例 (3)部署LLaMA3.1 (4)使用教程 总结 前言 LLama3…...

Spring Boot 配置全流程 总结
1. 简介 Springboot可以简化SSM的配置,提高开发效率。 2. 代码 在pom.xml中添加: <parent><!-- 包含SSM常用依赖项 --><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</art…...

爬虫技术初步自学
目的 本篇文章实际上自学爬虫技术的学习一份学习笔记,希望可以对后学的小白起到帮助,也希望得到大佬的指点,若有错漏希望大佬指出。 初步认知 爬虫实际上是一个计算机程序。开发爬虫程序的常用语言是Python。(Python我已经在五…...

【力扣 | SQL题 | 每日三题】力扣175, 176, 181
1. 力扣175:组合两个表 1.1 题目: 表: Person ---------------------- | 列名 | 类型 | ---------------------- | PersonId | int | | FirstName | varchar | | LastName | varchar | ---------------------- personId 是该…...

SpringBoot使用hutool操作FTP
项目场景: SpringBoot使用hutool操作FTP,可以实现从FTP服务器下载文件到本地,以及将本地文件上传到FTP服务器的功能。 实现步骤: 1、引入依赖 <dependency><groupId>commons-net</groupId><artifactId>…...

如何防止SQL注入攻击
SQL注入攻击是一种常见的网络安全威胁,攻击者通过在用户输入中插入恶意的SQL代码,从而可以执行未经授权的数据库操作。为了防止SQL注入攻击,我们可以采取一系列有效的措施来保护数据库和应用程序的安全性。以下是一些关键的防范策略ÿ…...

Java List类
欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:Java 目录 👉🏻List1. 接口与实现2. 特性3. 常用方法4. 示例代码5. 遍历6. 线程安全 👉🏻List Java的 List …...

使用 Internet 共享 (ICS) 方式分配ip
设备A使用dhcp的情况下,通过设备B分配ip并共享网络的方法。 启用网络共享(ICS)并配置 NAT Windows 自带的 Internet Connection Sharing (ICS) 功能可以简化 NAT 设置,允许共享一个网络连接给其他设备。 打开网络设置࿱…...

SMTP/IMAP服务发在线邮件时要用到
SMTP/IMAP服务 require PHPMailerAutoload.php; // 或 require class.phpmailer.php;// 创建实例 $mail new PHPMailer();// 设定邮件服务器 $mail->isSMTP(); $mail->Host smtp.example.com; // 邮件服务器地址 $mail->SMTPAuth true; $mail->Username your…...

Threejs绘制圆锥体
上一章节实现了胶囊体的绘制,这节来绘制圆锥体,圆锥体就是三角形旋转获得的,如上文一样,先要创建出基础的组件,包括场景,相机,灯光,渲染器。代码如下: initScene() {this…...

速通LLaMA3:《The Llama 3 Herd of Models》全文解读
文章目录 概览论文开篇IntroductionGeneral OverviewPre-TrainingPre-Training DataModel ArchitectureInfrastructure, Scaling, and EfficiencyTraining Recipe Post-TrainingResultsVision ExperimentsSpeech Experiments⭐Related WorkConclusionLlama 3 模型中的数学原理1…...

Python网络爬虫获取Wallhaven壁纸图片(源码)
** 话不多说,直接附源码,可运行! ** import requests from lxml import etree from fake_useragent import UserAgent import timeclass wallhaven(object):def __init__(self):# yellow# self.url "https://wallhaven.cc/search?co…...

智能化引领等保测评新时代:AI与大数据的深度融合
随着信息技术的飞速发展,等级保护测评(简称“等保测评”)作为保障信息系统安全的重要手段,正迎来前所未有的变革。在这一背景下,人工智能(AI)与大数据技术的深度融合,正引领等保测评…...

深入解析:HTTP 和 HTTPS 的区别
网络安全问题正变得日益重要,而 HTTP 与 HTTPS 对用户数据的保护十分关键。本文将深入探讨这两种协议的特点、工作原理,以及保证数据安全的 HTTPS 为何变得至关重要。 认识 HTTP 与 HTTPS HTTP 的工作原理 HTTP,全称超文本传输协议…...

《动手学深度学习》笔记1.11——实战Kaggle比赛:预测房价+详细代码讲解
目录 0. 前言 原书正文 1. 下载和缓存数据集 1.1 download() 下载数据集 1.2 download_extract() 解压缩 2. Kaggle 简介 3. 访问和读取数据集 4. 数据预处理 5. 训练(核心难点) 5.1 get_net() 定义模型-线性回归 5.2 log_rmse() 对数均方根…...

数据结构:单链表实现信息管理
一、函数声明部分 #ifndef __LINK_H__ #define __LINK_H__ #include <myhead.h> typedef struct Link1 {union{int len;//用于头结点,统计节点个数int data;//用于正常节点,存储数据};struct Link1 *next;//指针域 }Link,*Plink;/**********函数声…...

【Linux】解锁文件描述符奥秘,高效缓存区的实战技巧
fd和缓冲区 1. 文件描述符fd1.1. 概念与本质1.2. 打开文件的管理1.3. 一切皆文件的理解1.4. 分配规则1.5. 重定向的本质1.5.1. dup2 2. FILE中的缓冲区2.1. 概念2.2. 存在的原因2.3. 类型(刷新方案)2.4. 存放的位置2.4.1. 代码证明、现象解释 2.5. 模拟C标准库中的方法 1. 文件…...