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;

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

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

相关文章

Redis6.0.9配置redis集群

写在前面 最近在完成暑期大作业&#xff0c;期间要将项目部署在云服务器上&#xff0c;其中需要进行缓存的配置&#xff0c;决定使用Redis&#xff0c;为了使系统更加健壮&#xff0c;选择配置Redis-Cluster。由于服务器资源有限&#xff0c;在一台服务器上运行6个Redis Instan…

docker desktop windows stop

服务docker改为启动 cmd下查看docker版本 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://hub.atomgit.com/"]…

三目运算判断字母大小写-C语言

1.问题&#xff1a; 输入一个字符&#xff0c;判别它是否为大写字母&#xff0c;如果是&#xff0c;将它转换成小写&#xff0c;如果不是&#xff0c;不转换。然后输出最后得到的字符&#xff0c;要求使用三目运算符。 2.解答&#xff1a; 用条件表达式来处理&#xff0c;当字…

Go基础学习04-变量重声明;类型转换;类型断言;Unicode代码点;类型别名;潜在类型

目录 变量重声明 类型断言 类型转换 类型转换注意事项 Unicode代码点 类型别名、潜在类型 类型别名的意义 变量重声明 编写代码&#xff1a; package mainimport "fmt"var container []string{"Beijing", "Shanghai"}func main() {fmt.Pr…

快递物流短信API接口代码

官网&#xff1a;快递鸟 API参数 用户信息类 一.短信模版 1.接口说明 使用快递鸟短信功能时&#xff0c;预先设置好短信模板和对应的发送规则&#xff0c;快递鸟短信API将根据设置的好的模板和规则&#xff0c;进行短信的发送和反馈。 (1)仅支持Json格式。 (2)请求指令810…

数据结构-2.9.双链表

一.双链表与单链表的对比&#xff1a; 二.双链表的初始化(带头结点)&#xff1a; 1.图解&#xff1a; 2.代码演示&#xff1a; #include<stdio.h> #include<stdlib.h> ​ //定义双链表结构体 typedef struct DNode {int data;struct DNode *prior;//前驱指针即指…

软件测试基础面试题【最新-附带答案】

1、介绍一下你上一家公司的测试流程吧&#xff1f; 1、产品经理拿下项目 2、所有技术人员&#xff08;开发&#xff0c;测试&#xff0c;运维&#xff0c;UI&#xff09;召开需求分析会议 3、测试组内召开会议&#xff08;明确测试需求&#xff0c;分配人员任务&#xff09;…

Spring Boot 学习之路 -- Service 层

前言 最近因为业务需要&#xff0c;被拉去研究后端的项目&#xff0c;代码框架基于 Spring Boot&#xff0c;对我来说完全小白&#xff0c;需要重新学习研究…出于个人习惯&#xff0c;会以 Blog 文章的方式做一些记录&#xff0c;文章内容基本来源于「 Spring Boot 从入门到精…

(补充)3DMAX初级小白班第三课:创建物体+物体材质编辑

1.可以点这里来改变材质颜色&#xff08;但是通过材质编辑器给了材质以后就只能在这里改线框颜色&#xff09;。但一般就是用灰色材质和黑色线框 2.材质编辑器快捷键为m 右键可更改个数&#xff0c;最多24个 将材质指定选定对象 如何把材质编辑器面板改成旧版 按f10 改成扫描…

计算机毕设选题推荐-基于python的电子健康信息分析系统【源码+文档+调试】

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、电子健康信息…

【Linux】解锁管道通信和共享内存通信,探索进程间通信的海洋

目录 引言&#xff1a; 1、进程间通信基础介绍 1.1为什么需要在进程之间通信&#xff1f; 1.2进程间通信是什么&#xff1f; 1.3我们具体如何进行进程间的通信呢&#xff1f; a.一般规律&#xff1a; b.具体做法 2.管道 2.1什么是管道 2.2匿名管道&#xff1a; 创建…

行业展望:线缆行业发展

线缆行业作为国民经济中最大的配套行业之一&#xff0c;在我国机械工业的细分行业中占据举足轻重的地位&#xff0c;仅次于汽车整车制造和零部件及配件制造业。作为电气化、信息化、智能化社会中重要的基础性配套产业&#xff0c;电线电缆被誉为国民经济的"血管"与&q…

用户态缓存:链式缓冲区(Chain Buffer)

目录 链式缓冲区&#xff08;Chain Buffer&#xff09;简介 为什么选择链式缓冲区&#xff1f; 代码解析 1. 头文件与类型定义 2. 结构体定义 3. 宏定义与常量 4. 环形缓冲区的基本操作 5. 其他辅助函数 6. 数据读写操作的详细实现 7. 总结 8. 结合之前的内容 9. 具…

鸿蒙OpenHarmony【小型系统基础内核(进程管理任务)】子系统开发

任务 基本概念 从系统的角度看&#xff0c;任务Task是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源&#xff0c;并独立于其它任务运行。 OpenHarmony 内核中使用一个任务表示一个线程。 OpenHarmony 内核中同优先级进程内的任务统一调度、运…

STM32 map 文件浅析

目录 一、概述二、Section Cross References三、Removing Unused input sections from the image四、Memory Map of the image1、Local Symbols2、全局符号&#xff08;Global Symbols&#xff09; 五、Image Symbol Table六、Image component sizes 一、概述 .map 文件是编译…

【质优价廉】GAP9 AI算力处理器赋能智能可听耳机,超低功耗畅享未来音频体验!

当今世界&#xff0c;智能可听设备已经成为了流行趋势。随后耳机市场的不断成长起来&#xff0c;消费者又对AI-ANC&#xff0c;AI-ENC&#xff08;环境噪音消除&#xff09;降噪的需求逐年增加&#xff0c;但是&#xff0c;用户对于产品体验的需求也从简单的需求&#xff0c;升…

半导体器件制造5G智能工厂数字孪生物联平台,推进制造业数字化转型

半导体器件制造行业作为高科技领域的核心驱动力&#xff0c;正积极探索和实践以5G智能工厂数字孪生平台为核心的新型制造模式。这一创新不仅极大地提升了生产效率与质量&#xff0c;更为制造业的未来发展绘制了一幅智能化、网络化的宏伟蓝图。 在半导体器件制造5G智能工厂中&a…

Java笔试面试题AI答之设计模式(1)

文章目录 1. 简述什么是设计模式 &#xff1f;2. 叙述常见Java设计模式分类 &#xff1f;3. Java 设计模式的六大原则 &#xff1f;4. 简述对 MVC 的理解&#xff0c; MVC 有什么优缺点&#xff1f;MVC 的三个核心部分&#xff1a;MVC 的优点&#xff1a;MVC 的缺点&#xff1a…

巨潮股票爬虫逆向

目标网站 aHR0cDovL3dlYmFwaS5jbmluZm8uY29tLmNuLyMvSVBPTGlzdD9tYXJrZXQ9c3o 一、抓包分析 请求头参数加密 二、逆向分析 下xhr断点 参数生成位置 发现是AES加密&#xff0c;不过是混淆的&#xff0c;但并不影响咱们扣代码 文章仅提供技术交流学习&#xff0c;不可对目标服…

LabVIEW提高开发效率技巧----合理使用数据流与内存管理

理使用数据流和内存管理是LabVIEW开发中提高性能和稳定性的关键&#xff0c;特别是在处理大数据或高频率信号时&#xff0c;优化可以避免内存消耗过大、程序卡顿甚至崩溃。 1. 使用 Shift Register 进行内存管理 Shift Register&#xff08;移位寄存器&#xff09; 是 LabVIE…