平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“Mysql 数据库自定义函数实例”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
从实现思路看,MySQL自定义函数(Stored Function)就是你自己封装的一段可复用逻辑,定义后能像 NOW()、CONCAT() 这些内置函数一样,直接在 SQL 里调用,比如 SELECT get_score_level(86)。它常用来轻量的计算、格式化和数据转换,核心特点就是 必须得到一个值,而且只能得到一个。
前言
落到代码里,在MySQL里,很多人会混淆**自定义函数(UDF,用户自定义函数)**和存储过程,二者虽然都属于数据库可编程对象,但采用场景、语法限制、调用方式差异很大。
内置函数如SUM()、DATE_FORMAT()能够直接拿来用,但如果业务有固定的计算逻辑、格式化规则,反复写重复SQL就很繁琐,这时就能够自己编写MySQL自定义函数,封装逻辑,一行调用。
注意:MySQL自定义函数有得到值,必须得到单个值;不能得到结果集,这是和存储过程最核心的区别。
一、自定义函数基础语法
新建函数
DELIMITER //
CREATE FUNCTION 函数名(参数名 参数类型)
RETURNS 返回值类型
[DETERMINISTIC]
BEGIN
-- 函数业务逻辑
RETURN 返回的数据;
END //
DELIMITER ;
关键字说明:
DELIMITER //:修改语句结束符。默认MySQL以;作为结束标记,函数体内部会用到分号,所以临时改成//,函数新建完成再恢复;。CREATE FUNCTION:新建自定义函数。- 入参:只兼容IN输入参数,没有OUT、INOUT参数(存储过程才有)。
RETURNS:必须声明得到值的数据类型,int、varchar、datetime等。DETERMINISTIC(可选):确定函数。相同输入一定得到相同结果,不读随机数、当前时间这类动态数据,开启有助于优化器优化。RETURN:函数内部必须有return语句,得到结果。
查看、删除函数
-- 查看数据库下所有自定义函数
SHOW FUNCTION STATUS WHERE Db = '你的数据库名';
-- 删除自定义函数
DROP FUNCTION IF EXISTS 函数名;
二、轻松实战示例
示例1:最轻松的数字计算函数
需求:传入分数,得到等级。比如 >=90优秀,>=80良好,>=60及格,其余不及格。
DELIMITER //
CREATE FUNCTION get_score_level(score INT)
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
DECLARE level VARCHAR(20);
IF score >= 90 THEN
SET level = '优秀';
ELSEIF score >= 80 THEN
SET level = '良好';
ELSEIF score >= 60 THEN
SET level = '及格';
ELSE
SET level = '不及格';
END IF;
RETURN level;
END //
DELIMITER ;
调用方式(和内置函数一样,放在select里)
SELECT get_score_level(86);
-- 结合表查询
SELECT name, score, get_score_level(score) AS level FROM student;
示例2:文本处理函数
需求:传入字符串,去掉多余空格,转为大写得到
DELIMITER //
CREATE FUNCTION str_upper_trim(str VARCHAR(255))
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
RETURN UPPER(TRIM(str));
END //
DELIMITER ;
调用:
SELECT str_upper_trim(' hello mysql ');
三、自定义函数 VS 存储过程(重点区分)
| 对比项 | 自定义函数Function | 存储过程Procedure |
|---|---|---|
| 得到值 | 必须有且只能得到单个值 | 无得到值,能够用OUT输出多个参数 |
| 调用方式 | select 函数() | call 存储过程() |
| 参数类型 | 仅兼容IN输入参数 | 兼容IN/OUT/INOUT三种参数 |
| 得到结果集 | 不能得到多行结果集 | 能够查询得到结果集 |
| 事务 | 不建议在函数内采用事务 | 兼容事务、复杂业务逻辑 |
| 采用场景 | 轻松计算、字段格式化、转换 | 批量DML、复杂多步骤业务 |
一句话总结:轻松计算、字段转换用自定义函数;多表更新、批量操作、复杂业务流程用存储过程。
四、适用场景
- 字段格式化:统一对日期、文本、编码做清洗转换,查询时直接调用,避免每个SQL重复写一堆CASE、字符串处理逻辑。
- 固定规则计算:分数评级、税率计算、编码生成,规则写在函数里,后续修改只改函数,不用改所有业务SQL。
- 复杂字段判断:多条件的标签判定,比如根据金额、时间自动打业务标签。
五、重要限制与避坑
- 禁止在函数里做DML操作实际处理时,(insert/update/delete),容易出现锁、主从同步异常,MySQL不建议,部分版本直接限制。
- 不能得到多行数据,想查询多条记录不能用自定义函数,改用存储过程。
- 函数内尽量避免查询大表,函数会每行都执行,放在WHERE或者SELECT字段里,大数据量极易性能雪崩。
- 权限问题:新建函数需
CREATE ROUTINE权限,线上数据库最小权限原则,不要随意开放。 - 注意字符集、长度,varchar类型如果得到内容超出定义长度会截断。
六、什么时候不要用自定义函数
- 需批量新增、更新、删除数据 → 存储过程
- 需得到多行查询结果 → 存储过程
- 从实现思路看,逻辑很重、关联多张大表 → 尽量写原生SQL,函数会造成每行执行,索引失效风险高
- 逻辑经常频繁变更:函数修改需DDL锁,高同时发生产环境要谨慎。
结尾
实际处理时,MySQL自定义函数适合封装轻量、无副作用的计算转换逻辑,采用轻松,调用方式和内置函数保持一致。但它不是万能的,千万不要把复杂业务全部塞进函数,尤其是大数据量查询场景,很容易引发性能问题。开发前分清函数和存储过程的适用边界,才能发挥它的价值。
落到代码里,总的来说,mysql 自定义函数适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

