mysql存储函数必须声明returns类型且禁止执行insert/update/delete,本质是只读计算单元,仅用于select、where等表达式上下文,不可call调用,也不支持事务与错误捕获。

存储函数必须带 RETURNS,且不能执行 INSERT/UPDATE/DELETE
MySQL 存储函数本质是「只读计算单元」,它强制要求声明返回类型(如 RETURNS INT),且函数体内禁止修改数据——哪怕只是 INSERT INTO tmp_table 也会报错 ERROR 1418 (HY000)。这不是限制,而是设计契约:函数用于表达式上下文(SELECT、WHERE、ORDER BY),不是业务流程控制器。
- 想做数据变更?用
CREATE PROCEDURE+CALL - 想在
SELECT中复用逻辑?才该写CREATE FUNCTION - 函数体里出现
INSERT、UPDATE、DELETE或CALL其他过程,直接失败
DELIMITER 不是可选的,漏写会导致语法错误
MySQL 默认以分号 ; 为语句结束符,但函数定义里有多个分号(比如变量赋值、RETURN 前后),不改结束符就会被提前截断。常见错误是只写 DELIMITER // 却忘了结尾的 DELIMITER ;,结果后续所有命令都卡在函数定义里,直到你手动 Ctrl+C 中断。
- 正确顺序:
DELIMITER //→ 函数定义 →END //→DELIMITER ; - 如果用 Navicat 或 DBeaver,它们可能自动处理 delimiter,但命令行或脚本里必须显式写
- 执行完函数后记得恢复,否则下一条普通 SQL 会因找不到
;而报错
DETERMINISTIC 是性能关键,别随便省略
MySQL 默认把函数标记为 NOT DETERMINISTIC,这意味着每次调用都可能重新计算,无法被查询优化器缓存或下推。如果你的函数纯靠输入参数决定输出(比如 UPPER()、ABS()、自定义的 is_leap_year(year)),必须显式加 DETERMINISTIC,否则在大表 SELECT 中可能拖慢数倍。
- 加了
DETERMINISTIC后,函数结果可被 MySQL 缓存,同一行多次调用只算一次 - 若函数依赖系统时间(
NOW())、用户变量、临时表或外部状态,就不能加——加了反而导致结果错误 - 没加时,某些版本还会拒绝创建(尤其开启
log_bin_trust_function_creators=OFF的从库)
函数名不能和内置函数冲突,调用时也不加 schema 前缀
MySQL 查找函数时,优先匹配当前数据库下的自定义函数,再 fallback 到系统函数。如果重命名了 CONCAT 或 SUM,会导致后续所有含该函数的 SQL 报错或行为异常;更隐蔽的是,调用时写 mydb.myfunc() 会失败——函数名不支持库名限定,只能是裸名 myfunc()。
- 建之前先查:
SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = DATABASE() AND ROUTINE_TYPE = 'FUNCTION'; - 避免用
DATE、USER、VERSION这类关键字作函数名 - 跨库调用?不行。函数作用域仅限于当前 database,切换库要重新创建
DECLARE HANDLER。真正复杂的逻辑封装,该交给存储过程;函数只管“给一个答案”。











