乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

存储函数

导学

存储函数(Stored Function)与存储过程类似,但它必须有返回值,并且可以像内置函数一样嵌套在 SQL 语句中使用。本节学习如何创建和调用存储函数。

定义

存储函数:预编译并存储在数据库中的函数,接受参数(只能是 IN 模式),必须返回一个值。可以在 SQL 表达式的任何位置调用。

核心语法

DELIMITER //

CREATE FUNCTION 函数名(参数 类型)
RETURNS 返回类型
[特性声明]
BEGIN
    -- 逻辑
    RETURN 值;
END //

DELIMITER ;

完整示例一:计算加分后成绩的函数

当前数据状态

首先建立示例表并插入数据:

CREATE DATABASE IF NOT EXISTS school;
USE school;

DROP TABLE IF EXISTS employees;
CREATE TABLE employees (
    emp_id INT PRIMARY KEY AUTO_INCREMENT,
    emp_name VARCHAR(20),
    dept VARCHAR(20),
    score DECIMAL(5,2)
);

INSERT INTO employees (emp_name, dept, score) VALUES
('大翔', '技术部', 100),
('白歌', '技术部', NULL);

当前 employees 表数据:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

操作语句

创建计算加分后成绩的存储函数:

DELIMITER //

CREATE FUNCTION ScoreAfterBonus(score DECIMAL(5,2), bonus DECIMAL(5,2))
RETURNS DECIMAL(5,2)
DETERMINISTIC
BEGIN
    RETURN score + bonus;
END //

DELIMITER ;

-- 在 SQL 中像内置函数一样使用
SELECT emp_name, score, ScoreAfterBonus(score, 10) AS new_score FROM employees;

操作后的结果

返回:

emp_namescorenew_score
大翔100110
白歌NULLNULL

结果解读

ScoreAfterBonus(score, 10) 像内置函数一样嵌套在 SELECT 语句中,对每一行数据计算加分后的成绩。DETERMINISTIC 声明表示给定相同输入,函数总是返回相同输出。

完整示例二:格式化名字的函数

当前数据状态

基于 employees 表:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

操作语句

创建名字脱敏函数:

DELIMITER //

CREATE FUNCTION NameMask(name VARCHAR(20))
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
    IF name IS NULL OR LENGTH(name) < 2 THEN
        RETURN name;
    END IF;
    RETURN CONCAT(LEFT(name, 1), '*');
END //

DELIMITER ;

-- 使用函数查询
SELECT emp_name, NameMask(emp_name) AS masked_name FROM employees;

操作后的结果

返回:

emp_namemasked_name
大翔大*
白歌白*

结果解读

  • NameMask 函数对名字进行脱敏处理,保留第一个字,后面用 * 替代
  • 当 name 为 NULL 或长度不足2位时,直接原样返回,不做处理
  • 存储函数可以嵌套在 SELECT 列表、WHERE 子句、ORDER BY 等任何 SQL 表达式位置

完整示例三:在 WHERE 子句中使用存储函数

当前数据状态

基于 employees 表:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

操作语句

使用 ScoreAfterBonus 函数在 WHERE 子句中筛选:

-- 查询加分后成绩大于等于 110 的员工
SELECT emp_name, score, ScoreAfterBonus(score, 10) AS new_score
FROM employees
WHERE ScoreAfterBonus(score, 10) >= 110;

操作后的结果

返回:

emp_namescorenew_score
大翔100110

结果解读

存储函数可以嵌套在 WHERE 条件中,实现复杂的筛选逻辑。这使得 SQL 查询更加灵活和可复用。注意在 WHERE 中使用函数可能导致索引失效,大数据量时需谨慎。

完整示例四:删除存储函数

操作语句

-- 安全删除:如果存在则删除
DROP FUNCTION IF EXISTS ScoreAfterBonus;

-- 删除后再调用会报错
-- SELECT ScoreAfterBonus(100, 10);  -- ERROR 1305 (42000): FUNCTION school.ScoreAfterBonus does not exist

结果解读

DROP FUNCTION IF EXISTS 安全删除函数。删除后该函数名不能再被调用,否则报 FUNCTION does not exist 错误。

函数特性声明

特性含义
DETERMINISTIC给定相同输入,总是返回相同输出(推荐声明)
NOT DETERMINISTIC给定相同输入,可能返回不同输出(如依赖当前时间)
READS SQL DATA函数读取数据
NO SQL函数不含 SQL
MODIFIES SQL DATA函数修改数据(不推荐在函数中修改数据)

⚠️ 注意:MySQL 5.7 默认启用 log_bin_trust_function_creators = OFF,创建函数需要 SUPER 权限,或设置该参数为 ON。因为函数可能在复制中造成不确定性。

解决权限限制的示例:

-- 需要 SUPER 权限执行
SET GLOBAL log_bin_trust_function_creators = 1;

完整示例五:NOT DETERMINISTIC 函数

当前数据状态

基于 employees 表:

emp_idemp_namedeptscore
1大翔技术部100
2白歌技术部NULL

操作语句

创建一个依赖当前时间的非确定性函数:

DELIMITER //

CREATE FUNCTION GetCurrentYear()
RETURNS INT
NOT DETERMINISTIC
BEGIN
    RETURN YEAR(NOW());
END //

DELIMITER ;

-- 使用
SELECT emp_name, GetCurrentYear() AS current_year FROM employees;

操作后的结果

返回(结果随执行时间变化):

emp_namecurrent_year
大翔2026
白歌2026

结果解读

NOT DETERMINISTIC 声明表示函数输出可能随时间或其他外部因素变化。NOW() 每次执行返回不同的时间戳,因此相同输入可能产生不同输出。未声明时 MySQL 默认 NOT DETERMINISTIC,可能影响复制和查询缓存。

存储函数 vs 存储过程

特性存储函数存储过程
返回值必须有 1 个可以没有或有多个(结果集)
调用方式嵌套在 SQL 中CALL 调用
参数模式只能 ININ、OUT、INOUT
使用场景计算、转换复杂业务流程
返回结果集不可以可以

常见误区

误区正解
函数可以修改数据技术上可以,但极不推荐。函数应只负责计算和返回。
函数不需要声明 DETERMINISTIC建议声明。未声明时 MySQL 默认 NOT DETERMINISTIC,可能影响复制。
函数和存储过程完全等价调用方式和使用场景不同,不可完全互换。

面试考点

Q:存储函数和存储过程的区别?

函数必须有返回值,只能有 IN 参数,可以嵌套在 SQL 表达式中;过程通过 CALL 调用,可以有 IN/OUT/INOUT 参数,可以返回多个结果集,不能嵌套在 SQL 中。

Q:为什么函数中不建议修改数据?

函数的设计目的是计算和返回值。在函数中修改数据会导致副作用,使代码难以理解和维护,也可能在复制环境中造成问题。

Q:DETERMINISTIC 和 NOT DETERMINISTIC 的区别?

DETERMINISTIC 表示相同输入总是产生相同输出(如字符串拼接);NOT DETERMINISTIC 表示输出可能变化(如依赖 NOW())。声明 DETERMINISTIC 有助于优化器缓存结果。

小结

  • 存储函数必须有返回值,可以嵌套在 SQL 中使用
  • 参数只能是 IN 模式
  • 建议声明 DETERMINISTIC 特性
  • 函数应只做计算,不应修改数据

下一章引子:存储过程和函数中需要使用变量来临时存储数据,MySQL 提供了丰富的变量机制。

上一页
存储过程
下一页
变量