以下是对 MySQL 自定义函数(存储函数) 的总结,涵盖创建、使用、管理与注意事项。
一、什么是自定义函数
自定义函数(Stored Function)是用户自己编写的、可重复使用的 SQL 代码块,接收零或多个参数,通过计算返回一个单一值。可以直接在 SQL 语句中像内置函数一样调用。
二、创建函数的语法
DELIMITER $$
CREATE FUNCTION 函数名(参数1 类型1, 参数2 类型2, ...)
RETURNS 返回值类型
[DETERMINISTIC | NOT DETERMINISTIC] -- 特性声明
[SQL SECURITY {DEFINER | INVOKER}] -- 权限上下文
[COMMENT '描述']
BEGIN
-- 函数体:变量声明、流程控制、RETURN 语句
RETURN 表达式;
END$$
DELIMITER ;关键点:
- 参数只允许
IN(输入),不能指定OUT或INOUT。 - 函数体必须包含至少一条
RETURN语句。 - 需要先使用
DELIMITER临时更换结束符,避免语句被错误截断。
三、函数特性选项
创建时需合理声明特性,影响复制与优化:
| 选项 | 含义 |
|---|---|
DETERMINISTIC | 同一输入总是返回相同结果(用于主从复制、生成列等) |
NOT DETERMINISTIC | 返回值可能变化(默认) |
CONTAINS SQL | 函数体包含 SQL 语句,但不读写数据(默认) |
NO SQL | 不包含 SQL 语句 |
READS SQL DATA | 只读取数据(SELECT),不修改 |
MODIFIES SQL DATA | 会修改数据(INSERT/UPDATE/DELETE) |
注意: 默认特性为 NOT DETERMINISTIC, CONTAINS SQL。若函数只读且确定性,建议显式声明,否则创建生成列或函数索引时会失败。
四、函数体常用语法
1. 变量声明与赋值
DECLARE 变量名 数据类型 [DEFAULT 默认值];
SET 变量名 = 表达式;2. 条件判断
IF 条件 THEN
...
ELSEIF 条件 THEN
...
ELSE
...
END IF;或使用 CASE WHEN 表达式。
3. 循环
WHILE 条件 DO
...
END WHILE;
REPEAT
...
UNTIL 条件 END REPEAT;
loop_label: LOOP
...
IF 条件 THEN LEAVE loop_label; END IF;
END LOOP;五、完整示例
示例 1:拼接全名
DELIMITER $$
CREATE FUNCTION full_name(first_name VARCHAR(50), last_name VARCHAR(50))
RETURNS VARCHAR(101)
DETERMINISTIC
BEGIN
RETURN CONCAT(first_name, ' ', last_name);
END$$
DELIMITER ;
-- 调用
SELECT full_name('张', '三'); -- 返回 '张 三'示例 2:计算阶乘(递归不安全,用循环)
DELIMITER $$
CREATE FUNCTION factorial(n INT)
RETURNS BIGINT
DETERMINISTIC
BEGIN
DECLARE result BIGINT DEFAULT 1;
WHILE n > 1 DO
SET result = result * n;
SET n = n - 1;
END WHILE;
RETURN result;
END$$
DELIMITER ;
-- 调用
SELECT factorial(5); -- 返回 120六、调用函数
在 SQL 语句中直接使用,与内置函数完全一致:
SELECT full_name(first_name, last_name) FROM users;
UPDATE table SET col = 函数名(参数);七、查看与删除
-- 查看所有自定义函数(当前库)
SHOW FUNCTION STATUS WHERE Db = '数据库名';
-- 查看函数创建语句
SHOW CREATE FUNCTION 函数名;
-- 删除函数
DROP FUNCTION IF EXISTS 函数名;修改函数: MySQL 不支持 ALTER FUNCTION 直接修改函数体,只能修改特性(COMMENT 等)。如需变更逻辑,须 DROP 后重新 CREATE。
八、与存储过程的区别
| 对比项 | 自定义函数 | 存储过程 |
|---|---|---|
| 返回值 | 必须返回一个值 | 可通过 OUT 参数返回多个值,也可无返回值 |
| 调用方式 | 嵌入 SQL 中调用 | CALL 存储过程名(参数); |
| 参数模式 | 仅 IN | IN、OUT、INOUT |
| 使用场景 | 计算、转换、封装逻辑后用于查询 | 批量处理、事务操作、复杂业务流 |
九、重要注意事项
-
禁止在函数内修改数据
通常自定义函数应只读(READS SQL DATA或NO SQL)。若函数内包含INSERT/UPDATE/DELETE,极易导致主从复制不一致、触发器意外激活或日志记录错误。在只读从库上调用时会失败。 -
二进制日志安全
声明函数为DETERMINISTIC且不修改数据,才能安全地用于主从复制与生成列。若声明与行为不符,复制可能出错。 -
性能
函数在 SQL 中对每一行都会执行,避免在大量数据上使用复杂计算的函数。可改用查询表达式或应用层处理。 -
权限
- 创建函数:需要
CREATE ROUTINE权限。 - 执行函数:需要
EXECUTE权限。 - 修改/删除:需
ALTER ROUTINE权限及函数所属数据库的ALTER/DROP权限。
- 创建函数:需要
-
函数名区分大小写
取决于操作系统和数据库配置,建议统一使用小写加下划线。
十、用户自定义函数扩展(C语言 UDF)
MySQL 还支持使用 C/C++ 编写动态加载的 用户定义函数(UDF),通过 CREATE FUNCTION ... SONAME '库文件名' 加载。这种方式功能更强大但安全风险高,不适合常规业务,通常使用存储函数即可。本总结仅针对存储函数。
合理使用自定义函数可以大幅简化 SQL 逻辑,但要谨记“只读、确定性、轻量”三原则,确保系统稳定。