ℹ️大家好,我是练小杰,今天周五了,一周就这样从手上溜走了,还有两星期过年!!
本文将学习MYSQL中存储过程与存储函数的概念~~
回顾:【索引详解】【索引相关练习】
数据库专栏【数据库专栏】~
想要了解更多内容,主页 【练小杰的CSDN】
存储过程是一组预编译的 SQL 语句集合,可以接受输入参数、执行操作并返回结果集或输出参数。它类似于编程语言中的函数或方法,但主要目的是执行一系列数据库操作。
特点:
CALL
语句调用。存储函数是一组预编译的 SQL 语句集合,主要用于执行计算并返回一个单一的值。它类似于编程语言中的函数,可以用在 SQL 语句中,如 SELECT、WHERE 子句等。
特点:
RETURN
语句返回一个单一的值。存储过程: 若需要执行一系列数据库操作、批量处理数据或执行复杂的业务逻辑,使用存储过程更方便。
存储函数: 若需要在 SQL 查询中进行简单的计算、数据转换或逻辑判断时,使用存储函数更好。
CREATE PROCEDURE
语句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
例如:
BEGIN
SELECT * FROM employees WHERE department_id = dept_id;
END
CREATE FUNCTION
语句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
块内使用,且必须在任何其他语句之前声明变量。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 后跟一个常量值或表达式。
DECLARE total INT DEFAULT 0;
DECLARE name VARCHAR(100) DEFAULT 'Unknown';
SET 是用于在 MySQL 的存储过程(Stored Procedure)、存储函数(Stored Function)或其他编程结构中为变量赋值的基本命令。
SET var_name = expr [, var_name = expr] ...;
SET
: 用于为变量赋值,可以一次为多个变量赋值,变量之间用逗号分隔。
var_name
: 指定要赋值的变量名称
- 用户定义的变量以
@
符号开头,例如@total
。- 局部变量在存储过程或函数内部使用
DECLARE
声明的变量- 系统变量是在 MySQL 提供的变量,例如
@@session.sql_mode
expr
:指定赋给变量的值或表达式,可以是常量、表达式、函数调用、另一个变量的值等。
定义条件用于为特定的错误代码或 SQLSTATE 值指定一个名称。
DECLARE condition_name CONDITION FOR condition_value;
condition_name
:为条件指定的名称。
condition_value
:
- SQLSTATE [VALUE] sqlstate_value:使用 SQLSTATE 值来定义条件。
- MySQL_error_code :使用 MySQL 错误代码来定义条件。
-- 使用 SQLSTATE 值定义条件
DECLARE duplicate_key CONDITION FOR SQLSTATE '23000';
-- 使用 MySQL 错误代码定义条件
DECLARE division_by_zero CONDITION FOR 1146;
处理程序用于定义在特定条件发生时,存储过程或函数应采取的操作。
处理程序可以处理SQLWARNING、NOT FOUND
和SQLEXCEPTION
等通用条件,也可以处理通过DECLARE CONDITION
定义的特定条件。
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)
SELECT
查询DECLARE cursor_name CURSOR FOR select_statement;
cursor_name
:光标的名称。
select_statement
:用于定义光标结果集的 SELECT 查询。
DECLARE emp_cursor CURSOR FOR
SELECT employee_id, name, salary FROM employees;
为了处理光标遍历过程中可能出现的异常(如未找到数据),可以声明相应的处理程序。
DECLARE CONTINUE HANDLER FOR NOT FOUND
BEGIN
-- 处理未找到数据的逻辑
END;
开始遍历结果集之前,需要打开光标
OPEN cursor_name;
使用
FETCH
语句从光标中获取一行数据,并将其存储到变量中。
var_name
用于存储每一列数据的变量。
FETCH cursor_name INTO var_name [, var_name] ...;
获取数据后,可以对数据进行所需的处理,如插入、更新或其他操作
INSERT INTO processed_employees (employee_id, name, salary)
VALUES (emp_id, emp_name, emp_salary);
处理完所有数据后,需要关闭光标以释放资源。
CLOSE cursor_name;
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 FOR
SELECT employee_id, name, salary, department FROM employees;
-- 打开光标
OPEN emp_cursor;
-- 开始循环遍历光标数据
read_loop: LOOP
FETCH emp_cursor INTO emp_id, emp_name, emp_salary, emp_department;
IF done THEN
LEAVE read_loop;
END IF;
-- 在这里可以对每一行数据进行操作
-- 例如,更新员工的工资
UPDATE employees SET salary = emp_salary * 1.1 WHERE employee_id = emp_id;
END LOOP;
-- 关闭光标
CLOSE emp_cursor;
END //
DELIMITER ;
根据条件执行不同的代码块,与C语言中的if 条件语句类似。
IF condition THEN
-- 条件为真时执行的语句
[ELSEIF condition THEN
-- 另一个条件为真时执行的语句]
[ELSE
-- 所有条件都不满足时执行的语句]
END IF;
提供多条件分支,类似于C语言编程中的 switch 语句。
CASE case_expression
WHEN value1 THEN result1
WHEN value2 THEN result2
...
[ELSE default_result]
END
创建一个简单的无限循环,需要使用
LEAVE
语句来退出循环。
label_name: LOOP
-- 循环体
IF condition THEN
LEAVE label_name;
END IF;
END LOOP label_name;
LEAVE loop_label;
用于跳过当前循环的剩余部分,开始下一次循环。
ITERATE loop_label;
创建一个重复执行代码块的循环,直到指定的条件为真。
label_name: REPEAT
-- 循环体
UNTIL condition
END REPEAT label_name;
与
REPEAT
语句功能类似, 创建一个重复执行代码块的循环,只要指定的条件为真。
label_name: WHILE condition DO
-- 循环体
END WHILE label_name;
存储过程的调用是通过
CALL
语句进行调用的。
CALL sp_name([parameter[,...]])
存储函数的使用方法与MySQL内部函数的使用方法是一样的。
状态
SHOW STATUS
语句可以查看存储过程和存储函数的状态SHOW {PROCEDURE | FUNCTION} STATUS
[LIKE 'pattern']
定义
SHOW CREATE
语句查看存储过程和存储函数的状态。SHOW CREATE {PROCEDURE | FUNCTION} sp_name
信息
MySQL中存储过程和函数的信息存储在
information_schema
数据库下的Routines
表中。
可以通过查询该表的记录来查询存储过程和函数的信息。
SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME=' sp_name ' ;
使用ALTER语句可以修改存储过程或函数的特性。
ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
删除存储过程和存储函数,可以使用
DROP
语句。
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
CREATE TABLE sch(id INT, name VARCHAR(50),glass VARCHAR(50));
INSERT INTO sch VALUE(1,'xiaoming','glass 1'), (2,'xiaojie','glass 2');
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
来查看插入表格的内容,结果如下:+------+----------+---------+
| id | name | glass |
+------+----------+---------+
| 1 | xiaoming | glass 1 |
| 2 | xiaojie | glass 2 |
+------+----------+---------+
2 rows in set (0.01 sec)
sch
中的记录数为count_sch()
,代码如下:CREATE FUNCTION count_sch()
RETURNS INT
RETURN (SELECT COUNT(*) FROM sch);
DELIMITER //
CREATE FUNCTION count_sch()
RETURNS INT
RETURN (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()
查看函数执行的情况,这个表中只有两条记录,得到的结果也是两条记录,说明存储函数成功的执行。
创建一个存储过程add_id在同时使用前面创建的存储函数返回表sch中的记录数,计算出表中所有的id之和。代码如下:
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()
获取的,是在存储过程中调用了存储函数。
DELIMITER //
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 //
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号相加。
本文有关mysql存储过程与存储函数的内容已经讲完了,明天再见啦!!
欢迎查看主页 【练小杰的CSDN】
ℹ️欢迎各位在评论区踊跃讨论,积极提出问题,解决困惑!!!
⚠️若博客里的内容有问题,欢迎指正,我会及时修改!!