我在广州学 Mysql 系列——存储过程与存储函数详解

embedded/2025/1/11 7:49:29/

ℹ️大家好,我是练小杰,今天周五了,一周就这样从手上溜走了,还有两星期过年!!
本文将学习MYSQL中存储过程与存储函数的概念~~
回顾:👉【索引详解】【索引相关练习】
数据库专栏👉【数据库专栏】~
想要了解更多内容,主页 【练小杰的CSDN】

在这里插入图片描述

文章目录

  • 存储过程与存储函数
    • 存储过程(Stored Procedure)
    • 存储函数(Stored Function)
    • ⚠️主要区别
    • 选择存储过程还是存储函数
  • 创建存储过程
    • 命令解释
  • 创建存储函数
    • 命令解释
  • 变量的使用
    • 定义变量
    • 为变量赋值
  • 定义条件和处理程序
    • 定义条件(Condition Definitions)
    • 处理程序(Handlers)
  • 光标的使用
    • 使用光标的步骤
    • 1.声明光标(DECLARE CURSOR)
    • 2. 声明处理程序(可选)
    • 3. 打开光标(OPEN CURSOR)
    • 4. 获取光标数据(FETCH CURSOR)
    • 5. 处理数据
    • 6. 关闭光标(CLOSE CURSOR)
    • 综合实例
  • 流程控制的使用
    • IF语句
    • CASE语句
    • LOOP语句
    • LEAVE语句
    • ITERATE语句
    • REPEAT语句
    • WHILE语句
  • 调用存储过程和存储函数
    • 调用存储过程
    • 调用存储函数
  • 查看存储过程和存储函数
    • 查看存储过程和存储函数的`状态`
    • 查看存储过程和存储函数的`定义`
    • 查看存储过程和存储函数的`信息`
  • 修改存储过程和存储函数
  • 删除存储过程和存储函数
  • 综合案例
    • 创建一个存储函数用来统计表`sch`中的记录数
    • 创建一个存储过程,通过调用存储函数的方法来获取表sch中的记录数和sch表中id的和

在这里插入图片描述

存储过程与存储函数

存储过程(Stored Procedure)

存储过程是一组预编译的 SQL 语句集合,可以接受输入参数、执行操作并返回结果集或输出参数。它类似于编程语言中的函数或方法,但主要目的是执行一系列数据库操作。

  • 特点:

    1. 参数类型:可以有输入参数(IN) 、输出参数(OUT)和输入输出参数(INOUT)
    2. 返回值: 可以通过输出参数返回多个值或结果集,但不支持像函数那样直接返回一个单一的值。
    3. 调用方式: 使用 CALL 语句调用。
    4. 用途: 适用于执行复杂的业务逻辑、批量操作、数据迁移等。

存储函数(Stored Function)

存储函数是一组预编译的 SQL 语句集合,主要用于执行计算并返回一个单一的值。它类似于编程语言中的函数,可以用在 SQL 语句中,如 SELECT、WHERE 子句等。

  • 特点:

    1. 参数类型: 只能有输入参数(IN)。
    2. 返回值: 必须有一个 RETURN 语句返回一个单一的值。
    3. 调用方式: 可以像内置函数一样在 SQL 语句中使用。
    4. 用途: 适用于执行简单的计算、逻辑判断、数据转换等

⚠️主要区别

在这里插入图片描述

选择存储过程还是存储函数

  • 存储过程: 若需要执行一系列数据库操作、批量处理数据或执行复杂的业务逻辑,使用存储过程更方便。

  • 存储函数: 若需要在 SQL 查询中进行简单的计算、数据转换或逻辑判断时,使用存储函数更好。

创建存储过程

  • 创建存储过程,使用CREATE PROCEDURE语句
sql">CREATE PROCEDURE  sp_name ([proc_parameter[,...]])  [characteristics ...]routine_body

命令解释

  • CREATE PROCEDURE : 用于创建一个新的存储过程,后面跟存储过程的名称。
  • sp_name: 指定存储过程的名称。
  • [proc_parameter[,...]] : 存储过程的参数列表

参数类型包括:

IN: 输入参数(默认类型)。用于将值传递给存储过程。
OUT: 输出参数。用于从存储过程返回值给调用者。
INOUT: 输入输出参数。既可以接收调用者传递的值,也可以返回修改后的值。

  • [characteristics ...]: 指定存储过程的特性或选项
  • 常见的特性如下:

LANGUAGE SQL:指定存储过程使用的语言为 SQL(这是默认设置)


DETERMINISTIC :表示相同的输入参数总是产生相同的结果。


NOT DETERMINISTIC(默认):表示相同的输入参数可能产生不同的结果。


CONTAINS SQL:存储过程包含 SQL 语句,但不读取或修改数据。


NO SQL:存储过程不包含 SQL 语句。


READS SQL DATA:存储过程读取数据,但不修改数据。


MODIFIES SQL DATA(默认):存储过程修改数据。


SQL SECURITY DEFINER | INVOKER

  • DEFINER (默认):存储过程以定义者的权限执行。
  • INVOKER:存储过程以调用者的权限执行。

  • routine_body : 包含存储过程的主体逻辑,即一系列的 SQL 语句。
  • 使用 BEGINEND 包含多个语句,或者单个语句不需要 BEGIN…END

例如:

sql"> BEGINSELECT * FROM employees WHERE department_id = dept_id;END

创建存储函数

  • 创建存储过程,使用CREATE FUNCTION语句
sql">CREATE FUNCTION func_name ([func_parameter[,...]])RETURNS type [characteristic ...]routine_body

命令解释

  • CREATE FUNCTION : 用于创建一个新的存储函数,后跟函数的名称。

  • func_name: 指定存储函数的名称。

  • ([func_parameter[,...]]) : 定义存储函数的参数列表,参数类型只有 IN 参数(默认),用于将值传递给函数。例如,(salary DECIMAL(10,2))

  • RETURNS type: 指定函数返回值的类型,如 INT、VARCHAR(15)、DECIMAL(10,2)

  • [characteristic ...]: 指定存储函数的特性或选项,常见特性看上面!!

  • routine_body: 一系列的 SQL 语句,与存储过程的语法一样

变量的使用

定义变量

  • DECLARE 是用于在 MySQL 的存储过程(Stored Procedure)或存储函数(Stored Function)内部声明局部变量的命令。
  • DECLARE 语句只能在存储过程或存储函数的 BEGIN...END 块内使用,且必须在任何其他语句之前声明变量。
  • 基本语法:
sql">DECLARE var_name[,varname]… date_type [DEFAULT value];
  • 说明:

DECLARE: 用于声明一个或多个局部变量。
var_name [, var_name] ... : 指定要声明的一个或多个变量名称
data_type : 指定变量的数据类型, 如 INT、VARCHAR(50)、DECIMAL(10,2)、DATE等。
[DEFAULT value] : 为变量指定一个默认值。如果声明变量时没有提供 DEFAULT 子句,变量将被初始化为 NULL。 DEFAULT 后跟一个常量值或表达式。

  • 实例:
sql">DECLARE total INT  DEFAULT 0;  
DECLARE name VARCHAR(100) DEFAULT 'Unknown';

为变量赋值

SET 是用于在 MySQL 的存储过程(Stored Procedure)、存储函数(Stored Function)或其他编程结构中为变量赋值的基本命令。

sql">SET var_name = expr [, var_name = expr] ...;
  • 说明:

SET : 用于为变量赋值,可以一次为多个变量赋值,变量之间用逗号分隔。
var_name : 指定要赋值的变量名称

  • 用户定义的变量以 @ 符号开头,例如 @total
  • 局部变量在存储过程或函数内部使用 DECLARE 声明的变量
  • 系统变量是在 MySQL 提供的变量,例如 @@session.sql_mode

expr:指定赋给变量的值或表达式,可以是常量、表达式、函数调用、另一个变量的值等。

定义条件和处理程序

定义条件(Condition Definitions)

定义条件用于为特定的错误代码或 SQLSTATE 值指定一个名称。

  • 基本语法
sql">DECLARE condition_name CONDITION FOR condition_value;
  • 说明

condition_name:为条件指定的名称。


condition_value

  • SQLSTATE [VALUE] sqlstate_value:使用 SQLSTATE 值来定义条件。
  • MySQL_error_code :使用 MySQL 错误代码来定义条件。
  • 实例:
sql">-- 使用 SQLSTATE 值定义条件
DECLARE duplicate_key CONDITION FOR SQLSTATE '23000';-- 使用 MySQL 错误代码定义条件
DECLARE division_by_zero CONDITION FOR 1146;

处理程序(Handlers)

处理程序用于定义在特定条件发生时,存储过程或函数应采取的操作。
处理程序可以处理 SQLWARNING、NOT FOUNDSQLEXCEPTION 等通用条件,也可以处理通过 DECLARE CONDITION 定义的特定条件。

  • 基本语法:
sql">DECLARE handler_type HANDLER FOR condition_value [, condition_value] ... handler_statements;
  • 说明

handler_type

  • CONTINUE:在处理程序执行后,继续执行存储过程或函数中的下一个语句。
  • EXIT:在处理程序执行后,退出当前的 BEGIN…END 块。
  • UNDO(MySQL 不支持):回滚当前事务并退出块。

condition_value

  • SQLSTATE [VALUE] sqlstate_value:使用 SQLSTATE 值。
  • MySQL_error_code:使用 MySQL 错误代码。
  • condition_name:之前使用 DECLARE CONDITION 定义的名称。
  • SQLWARNING:匹配所有以 ‘01’ 开头的 SQLSTATE 值。
  • NOT FOUND:匹配所有以 ‘02’ 开头的 SQLSTATE 值。
  • SQLEXCEPTION:匹配所有未由 SQLWARNING 或 NOT FOUND 捕获的 SQLSTATE 值。

handler_statements:当条件发生时执行的 SQL 语句

光标的使用

光标(Cursor) 是一种用于在存储过程或存储函数中逐行处理查询结果的机制。光标允许你遍历 SELECT 语句返回的结果集,并逐行处理每一行数据。

使用光标的步骤

  1. 声明光标(DECLARE CURSOR)
  2. 打开光标(OPEN CURSOR)
  3. 获取光标数据(FETCH CURSOR)
  4. 处理数据
  5. 关闭光标(CLOSE CURSOR)

1.声明光标(DECLARE CURSOR)

  • 首先,需要声明一个光标,并指定其对应的 SELECT 查询
sql">DECLARE cursor_name CURSOR FOR select_statement;

cursor_name:光标的名称。
select_statement:用于定义光标结果集的 SELECT 查询。

  • 举例
sql">DECLARE emp_cursor CURSOR FOR
SELECT employee_id, name, salary FROM employees;

2. 声明处理程序(可选)

为了处理光标遍历过程中可能出现的异常(如未找到数据),可以声明相应的处理程序。

sql">DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN-- 处理未找到数据的逻辑
END;

3. 打开光标(OPEN CURSOR)

开始遍历结果集之前,需要打开光标

sql">OPEN cursor_name;

4. 获取光标数据(FETCH CURSOR)

使用 FETCH 语句从光标中获取一行数据,并将其存储到变量中。
var_name 用于存储每一列数据的变量。

sql">FETCH cursor_name INTO var_name [, var_name] ...;

5. 处理数据

获取数据后,可以对数据进行所需的处理,如插入、更新或其他操作

  • 举例:假设有一个表用于存储处理结果
sql">INSERT INTO processed_employees (employee_id, name, salary)
VALUES (emp_id, emp_name, emp_salary);

6. 关闭光标(CLOSE CURSOR)

处理完所有数据后,需要关闭光标以释放资源。

sql">CLOSE cursor_name;

综合实例

  • 演示如何使用光标逐行处理员工数据:
sql">DELIMITER //CREATE PROCEDURE ProcessEmployees()
BEGIN-- 声明变量用于存储光标数据DECLARE emp_id INT;DECLARE emp_name VARCHAR(100);DECLARE emp_salary DECIMAL(10,2);DECLARE emp_department VARCHAR(50);-- 声明一个标志变量,用于控制循环DECLARE done INT DEFAULT FALSE;-- 声明处理程序,处理光标遍历结束的情况DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;-- 声明光标DECLARE emp_cursor CURSOR FORSELECT employee_id, name, salary, department FROM employees;-- 打开光标OPEN emp_cursor;-- 开始循环遍历光标数据read_loop: LOOPFETCH emp_cursor INTO emp_id, emp_name, emp_salary, emp_department;IF done THENLEAVE read_loop;END IF;-- 在这里可以对每一行数据进行操作-- 例如,更新员工的工资UPDATE employees SET salary = emp_salary * 1.1 WHERE employee_id = emp_id;END LOOP;-- 关闭光标CLOSE emp_cursor;
END //DELIMITER ;

流程控制的使用

IF语句

根据条件执行不同的代码块,与C语言中的if 条件语句类似。

sql">IF condition THEN-- 条件为真时执行的语句
[ELSEIF condition THEN-- 另一个条件为真时执行的语句]
[ELSE-- 所有条件都不满足时执行的语句]
END IF;

CASE语句

提供多条件分支,类似于C语言编程中的 switch 语句。

sql">CASE case_expressionWHEN value1 THEN result1WHEN value2 THEN result2...[ELSE default_result]
END

LOOP语句

创建一个简单的无限循环,需要使用 LEAVE 语句来退出循环。

sql">label_name: LOOP-- 循环体IF condition THENLEAVE label_name;END IF;
END LOOP label_name;

LEAVE语句

  • 迭代控制语句,用于退出当前循环或块。
sql">LEAVE loop_label;

ITERATE语句

用于跳过当前循环的剩余部分,开始下一次循环。

sql">ITERATE loop_label;

REPEAT语句

创建一个重复执行代码块的循环,直到指定的条件为真。

sql">label_name: REPEAT-- 循环体UNTIL condition
END REPEAT label_name;

WHILE语句

REPEAT语句功能类似, 创建一个重复执行代码块的循环,只要指定的条件为真。

sql">label_name: WHILE condition DO-- 循环体
END WHILE label_name;

调用存储过程和存储函数

调用存储过程

存储过程的调用是通过CALL语句进行调用的。

sql">CALL sp_name([parameter[,...]])

调用存储函数

存储函数的使用方法与MySQL内部函数的使用方法是一样的。

查看存储过程和存储函数

查看存储过程和存储函数的状态

  • SHOW STATUS语句可以查看存储过程和存储函数的状态
sql">SHOW {PROCEDURE | FUNCTION} 	STATUS [LIKE 'pattern']

查看存储过程和存储函数的定义

  • SHOW CREATE语句查看存储过程和存储函数的状态。
sql">SHOW CREATE {PROCEDURE | FUNCTION} sp_name

查看存储过程和存储函数的信息

MySQL中存储过程和函数的信息存储在information_schema数据库下的Routines表中。
可以通过查询该表的记录来查询存储过程和函数的信息。

sql">SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=' sp_name ' ;

修改存储过程和存储函数

使用ALTER语句可以修改存储过程或函数的特性。

sql">ALTER {PROCEDURE | FUNCTION}   sp_name [characteristic ...]

删除存储过程和存储函数

删除存储过程和存储函数,可以使用DROP语句。

sql">DROP {PROCEDURE | FUNCTION} [IF  EXISTS] sp_name

综合案例

  • 创建一个sch表,并且向sch表中插入表格中的数据
    代码如下:
sql">CREATE TABLE sch(id INT, name VARCHAR(50),glass VARCHAR(50));
INSERT INTO sch VALUE(1,'xiaoming','glass 1'), (2,'xiaojie','glass 2');
  • 通过命令DESC命令查看创建的表格,结果如下:
sql"> DESC sch;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int         | YES  |     | NULL    |       |
| name  | varchar(50) | YES  |     | NULL    |       |
| glass | varchar(50) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
  • 通过SELECT * FROM sch来查看插入表格的内容,结果如下:
sql">+------+----------+---------+
| id   | name     | glass   |
+------+----------+---------+
|    1 | xiaoming | glass 1 |
|    2 | xiaojie  | glass 2 |
+------+----------+---------+
2 rows in set (0.01 sec)

创建一个存储函数用来统计表sch中的记录数

  • 创建一个可以统计表格内记录条数的存储函数,函数名为count_sch(),代码如下:
sql">CREATE FUNCTION count_sch() RETURNS INT RETURN (SELECT COUNT(*) FROM sch);
  • 执行的结果如下:
sql"> DELIMITER //CREATE FUNCTION count_sch()RETURNS INTRETURN (SELECT COUNT(*) FROM sch);//
Query OK, 0 rows affected (0.12 sec)SELECT count_sch() //DELIMITER ;
+-------------+
| count_sch() |
+-------------+
|      2   |
+-------------+
1 row in set (0.05 sec)

创建的储存函数名称为count_sch,通过SELCET count_sch()查看函数执行的情况,这个表中只有两条记录,得到的结果也是两条记录,说明存储函数成功的执行。

创建一个存储过程,通过调用存储函数的方法来获取表sch中的记录数和sch表中id的和

创建一个存储过程add_id在同时使用前面创建的存储函数返回表sch中的记录数,计算出表中所有的id之和。代码如下:

sql">CREATE PROCEDURE add_id(out count INT)
BEGIN
DECLARE itmp INT;
DECLARE cur_id CURSOR FOR SELECT id FROM sch; 
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_id;SELECT count_sch() INTO count;SET @sum=0;
OPEN cur_id;
REPEAT
FETCH cur_id INTO itmp;
IF itmp<10
THEN SET  @sum=  @sum+itmp;
END IF;
UNTIL 0 END REPEAT;
CLOSE cur_id;END ;

这个存储过程的代码中使用到了变量的声明、光标、流程控制、在存储过程中调用存储函数等知识点,结果是两条记录,id之和为3,记录条数是通过上面的存储函 count_sch()获取的,是在存储过程中调用了存储函数。

  • 代码的执行情况如下:
sql"> DELIMITER //CREATE PROCEDURE add_id(out count INT)BEGINDECLARE itmp INT;DECLARE cur_id CURSOR FOR SELECT id FROM sch;DECLARE EXIT HANDLER FOR NOT FOUND CLOSE cur_id;SELECT count_sch() INTO count;SET @sum=0;OPEN cur_id;REPEATFETCH cur_id INTO itmp;IF itmp<10THEN SET  @sum=  @sum+itmp;END IF;UNTIL 0 END REPEAT;CLOSE cur_id;END //
Query OK, 0 rows affected (0.00 sec)SELECT @a, @sum  //
+------+--------+
| @a  | @sum |
+------+--------+
|    2 |    3 |
+------+-------+
1 row in set (0.00 sec)DELIMITER ;

由上面代码知,表sch中只有两条记录,所有id的之和为3,和预想的执行结果完全相同。这个存储过程创建了一个cur_id的光标,使用这个光标来获取每条记录的id,使用REPEAT循环语句来实现所有id号相加。

本文有关sql>mysql存储过程与存储函数的内容已经讲完了,明天再见啦!!
😆 欢迎查看主页 【练小杰的CSDN】
ℹ️欢迎各位在评论区踊跃讨论,积极提出问题,解决困惑!!!
⚠️若博客里的内容有问题,欢迎指正,我会及时修改!!


http://www.ppmy.cn/embedded/152950.html

相关文章

数据结构——栈的实现

今天&#xff0c;我们来写一下关于栈的博文。 1.首先我们先了解一下什么是栈&#xff1f; 一&#xff1a;概念&#xff1a; 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端称为栈顶&#xff0c;另…

英伟达多维进击汽车业务:自动驾驶时代已至

英伟达此次发布的第四代Thor智驾计算平台&#xff0c;算力是上一代Orin平台的20倍。借助Thor&#xff0c;英伟达为车载计算机提供了强大的实时计算能力&#xff0c;支持多传感器融合&#xff0c;实现自动驾驶L4甚至L5级别的能力。2026财年&#xff0c;英伟达还将推出世界基础模…

doris:模型注意事项

建表时列类型建议​ Key 列必须在所有 Value 列之前。 尽量选择整型类型。因为整型类型的计算和查找效率远高于字符串。 对于不同长度的整型类型的选择原则&#xff0c;遵循够用即可。 对于 VARCHAR 和 STRING 类型的长度&#xff0c;遵循够用即可。 聚合模型的局限性​ …

如何修复三方库bug:marked.js 15.0.6 bug修复经过

marked一个非常流行的markdown格式解析器。 它在npmjs上的周下载量达500万之巨。 在其最新的version 15.0.6版本&#xff08;2025年1月8日使用&#xff09;&#xff0c;有处小bug&#xff1a;当在窄屏显示状态下&#xff0c;如手机端。代码会超出所在div&#xff0c;超出部分内…

Appium版本升级,需要注意哪些点:使用UiAutomator2Options传递capabilities

mac上安装的是较新的Appium版本&#xff0c;在跑之前写的Android UI 自动化代码时报错&#xff1a;AttributeError: dict object has no attribute to_capabilities。 查了一下资料&#xff0c;这是因为较新的 Selenium 和 Appium 版本要求使用 Options 类来定义能力&#xff…

解决pycharm中动态/静态出图的设置问题

1. pycharm中动态出图设置 import matplotlib matplotlib.use(TkAgg) # 强制使用 TkAgg 后端2. pycharm中静态出图设置 import matplotlib matplotlib.use(Agg) # 切换到非图形后端

【python基础——异常BUG】

什么是异常(BUG) 检测到错误,py编译器无法继续执行,反而出现错误提示 如果遇到错误能继续执行,那么就捕获(try) 1.得到异常:try的执行,try内只可以捕获一个异常 2.预案执行:except后面的语句 3.传入异常:except … as uestcprint(uestc) 4.没有异常:else… 5.鉴定完毕,收尾的语…

计算机网络之---物理层设备

什么是物理层设备 物理层设备是指负责数据在物理媒介上传输的硬件设备&#xff0c;它们主要处理数据的转换、信号的传输与接收&#xff0c;而不涉及数据的内容或意义。常见的物理层设备包括网卡、集线器、光纤收发器、调制解调器等。 物理层设备有哪些 1、网卡&#xff08;N…