ℹ️大家好,我是练小杰,今天周五了,一周就这样从手上溜走了,还有两星期过年!!
本文将学习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 语句集合,可以接受输入参数、执行操作并返回结果集或输出参数。它类似于编程语言中的函数或方法,但主要目的是执行一系列数据库操作。
-
特点:
- 参数类型:可以有输入参数(IN) 、输出参数(OUT)和输入输出参数(INOUT)
- 返回值: 可以通过输出参数返回多个值或结果集,但不支持像函数那样直接返回一个单一的值。
- 调用方式: 使用
CALL
语句调用。 - 用途: 适用于执行复杂的业务逻辑、批量操作、数据迁移等。
存储函数(Stored Function)
存储函数是一组预编译的 SQL 语句集合,主要用于执行计算并返回一个单一的值。它类似于编程语言中的函数,可以用在 SQL 语句中,如 SELECT、WHERE 子句等。
-
特点:
- 参数类型: 只能有输入参数(IN)。
- 返回值: 必须有一个
RETURN
语句返回一个单一的值。 - 调用方式: 可以像内置函数一样在 SQL 语句中使用。
- 用途: 适用于执行简单的计算、逻辑判断、数据转换等
⚠️主要区别
选择存储过程还是存储函数
-
存储过程: 若需要执行一系列数据库操作、批量处理数据或执行复杂的业务逻辑,使用存储过程更方便。
-
存储函数: 若需要在 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 语句。
- 使用
BEGIN
和END
包含多个语句,或者单个语句不需要 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 FOUND
和SQLEXCEPTION
等通用条件,也可以处理通过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
语句返回的结果集,并逐行处理每一行数据。
使用光标的步骤
- 声明光标(DECLARE CURSOR)
- 打开光标(OPEN CURSOR)
- 获取光标数据(FETCH CURSOR)
- 处理数据
- 关闭光标(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】
ℹ️欢迎各位在评论区踊跃讨论,积极提出问题,解决困惑!!!
⚠️若博客里的内容有问题,欢迎指正,我会及时修改!!