一、存储函数 vs. 存储过程

对比项 存储函数 (FUNCTION) 存储过程 (PROCEDURE)
返回值 必须通过 `RETURN` 语句返回单个结果值 可通过 `OUT`/`INOUT` 参数返回零个或多个结果,但本身没有直接返回值
主要用途 用于计算并返回一个结果,适合封装查询或表达式逻辑 用于执行较复杂的业务逻辑操作,例如增删改、流程控制、事务处理等
调用方式 可在 SQL 语句中直接调用(如 `SELECT`) 通过 `CALL` 语句进行调用
参数类型 参数默认为 `IN`(输入参数),不支持 `OUT`/`INOUT` 参数 参数可以是 `IN`、`OUT`、`INOUT`
二、创建存储函数 (CREATE FUNCTION)
基本语法:
CREATE FUNCTION function_name ([parameter_list]) RETURNS data_type [characteristic ...] routine_body
`function_name`: 存储函数名称。名称应保持唯一,实际开发中通常推荐使用 `func_` 前缀,便于管理与识别。
`parameter_list`: 参数列表。标准格式为:`[IN] param_name param_type`。由于存储函数参数只能是输入参数,因此 `IN` 关键字一般可以省略。
`param_name`: 参数名称。
`param_type`: 参数的数据类型,例如 `INT`、`VARCHAR(255)` 等。
`RETURNS data_type`: 必须明确声明函数返回值的数据类型,这是 MySQL 创建存储函数时的必要部分。
`characteristic`: 函数特性配置(可选),与存储过程中的特性定义类似。常见选项包括:
`DETERMINISTIC`:表示该函数是“确定性”的,也就是在相同输入条件下始终返回相同输出,例如常见数学计算函数。如果函数中使用了 `NOW()` 等非确定性函数,则不应声明为此选项。
`NOT DETERMINISTIC`:表示该函数是“非确定性”的,这也是默认设置。
`COMMENT 'string'`:用于添加函数注释说明,便于后续维护和查看。
`routine_body`: 函数体,由 `BEGIN ... END` 包裹的有效 SQL 语句组成,并且必须至少包含一个 `RETURN value` 语句来返回结果。
三、创建示例与步骤
在 MySQL 中创建存储函数时,通常需要临时修改语句分隔符,避免函数体内的 `;` 被错误识别为整个 SQL 语句结束符。
1. 选择数据库:
USE test;
2. 修改分隔符 (通常改为 `//` 或 `$$`):
DELIMITER //
3. 创建函数:
CREATE FUNCTION func_student(std_id INT)
RETURNS VARCHAR(20)
COMMENT '根据学生ID查询姓名'
BEGIN
声明一个变量用于保存查询结果
DECLARE student_name VARCHAR(20);
查询学生姓名并赋值给变量
SELECT name INTO student_name
FROM tb_student
WHERE id = std_id;
返回最终结果
RETURN(student_name);
END //
4. 恢复分隔符:
DELIMITER ;
示例 2:计算两个整数之和(更直观的入门示例)
DELIMITER //
CREATE FUNCTION func_add(a INT, b INT)
RETURNS INT
DETERMINISTIC
BEGIN
RETURN a + b;
END //
DELIMITER ;
四、调用存储函数
MySQL 存储函数可以在所有允许使用表达式的场景中调用,其中最常见的用法是在 `SELECT` 查询语句中直接使用:
调用示例1中的函数
SELECT func_student(1);
调用示例2中的函数
SELECT func_add(5, 3); -- 返回 8
在实际查询中使用函数
SELECT id, name, func_add(score, 10) AS new_score FROM tb_student;
五、管理存储函数
1. 查看函数
查看所有函数状态(支持模糊匹配):
SHOW FUNCTION STATUS LIKE 'func_%';
查看指定函数的定义:
SHOW CREATE FUNCTION func_student;
从 information_schema 信息模式中查询:
SELECT * FROM information_schema.ROUTINES
WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_NAME = 'func_student';
2. 修改函数
`ALTER FUNCTION` 语句主要用于修改注释、特性等元数据信息,不能直接修改函数体或参数定义。如果需要调整函数逻辑或参数,通常必须先 `DROP`,再重新 `CREATE`。
ALTER FUNCTION func_student COMMENT 'This is a new comment';
3. 删除函数
DROP FUNCTION IF EXISTS func_student;
`IF EXISTS` 属于可选写法,可避免在函数不存在时直接报错。
六、重要注意事项
1. 权限:创建 MySQL 存储函数通常需要具备 `CREATE ROUTINE` 权限。
2. 确定性:如果函数被声明为 `DETERMINISTIC`,但实际并非确定性函数,可能导致优化器做出错误判断,从而影响执行结果或查询计划。
3. RETURN 类型:`RETURN` 语句返回的值必须与 `RETURNS` 子句中声明的数据类型兼容,否则 MySQL 可能会进行隐式强制转换。
4. 需要特别注意,存储函数的函数体存在一定限制。它不能使用会触发显式或隐式提交(`COMMIT`)或回滚(`ROLLBACK`)的 SQL 语句。并且在一般情况下,也不允许直接修改数据库数据,例如 `INSERT`、`UPDATE`、`DELETE` 等语句通常都不能在存储函数中使用。因此,存储函数更适合用于结果计算、数据转换和查询封装,这一点与存储过程有明显区别。
