在实际的数据库开发中,面对重复的复杂计算(如多字段拼接、个性化数据校验、自定义统计逻辑),编写自定义函数能大幅提升代码复用性和开发效率。本章将从函数的基础概念出发,带你全面掌握 SQL 函数的定义、使用场景、执行方式和创建方法。
SQL 函数是一组预先定义(或自定义)的、可重复执行的代码块,它接收输入参数(可选),经过特定逻辑处理后返回一个或多个结果。你可以把它理解为一个 “数据处理工厂”:输入原材料(参数),经过工厂加工(函数逻辑),最终产出成品(返回值)。
从类型上看,SQL 函数主要分为两类:
内置函数:数据库系统自带的函数,无需创建即可直接使用,比如计算字符串长度的LENGTH()、求平均值的AVG()、日期转换的DATE_FORMAT()等。
自定义函数:由开发者根据业务需求自行编写的函数,用于实现内置函数无法满足的个性化逻辑。
举个例子:使用内置函数UPPER()将字符串转为大写
-- 执行内置函数,将"sql function"转为大写
> SELECT UPPER('sql function')
UPPER('sql function')|
---------------------+
SQL FUNCTION |
1 row(s) fetched.
在日常 SQL 开发中,函数的价值主要体现在以下 4 个方面:
(1)简化重复逻辑,提升代码复用性:如果你的业务中需要频繁执行某个计算(比如计算商品折扣价、用户年龄),无需每次都写重复的计算公式,只需将逻辑封装成函数,调用即可。例如:
-- 不使用函数:每次计算折扣价都要写重复逻辑 SELECT product_name, price * 0.8 AS discount_price FROM products; -- 使用函数:一次定义,多次调用,get_discount_price 是一个自定义的函数 SELECT product_name, get_discount_price(price) FROM products;
(2)降低代码复杂度,提升可读性:复杂的业务逻辑(比如多条件判断、嵌套计算)直接写在 SQL 语句中会让代码冗长且难以理解,封装成函数后,只需通过函数名即可清晰表达意图。
(3)统一数据处理规则,减少错误:通过函数固化数据处理逻辑(比如统一的日期格式转换、手机号脱敏规则),可以避免不同开发者编写不同逻辑导致的数据不一致问题。
(4)提升执行效率:数据库对函数有专门的优化机制,尤其是自定义函数,合理编写的函数能减少重复的查询和计算,降低数据库的执行压力。
执行(调用)SQL 函数是最基础的操作,不同类型的函数调用方式略有差异,但核心逻辑一致。
内置函数可直接在SELECT、WHERE、ORDER BY等子句中调用,语法为:函数名(参数1, 参数2, ...)。
常用内置函数示例:
-- 1. 字符串函数:拼接字符串
> SELECT CONCAT('Hello', ' ', 'SQL') AS result
result |
---------+
Hello SQL|
1 row(s) fetched.
-- 2. 数值函数:求绝对值
> SELECT ABS(-100) AS result
result|
------+
100|
1 row(s) fetched.
-- 3. 日期函数:获取当前日期
> SELECT CURDATE() AS result
result |
----------+
2026-01-08|
1 row(s) fetched.
-- 4. 聚合函数:计算订单总金额
> SELECT SUM(total_amount) AS total_amount FROM `order`
total_amount|
------------+
110379.00|
1 row(s) fetched.自定义函数创建完成后,调用方式与内置函数一致,只需确保函数名和参数匹配:
-- 调用自定义函数 get_user_age SELECT username, get_user_age(birthday) AS age FROM users;
注意,自定义 get_user_age 函数将在后续给出。
当内置函数无法满足业务需求时,你可以创建自定义函数(UDF,User-Defined Function)。不同数据库(MySQL、Oracle、SQL Server)的函数创建语法略有差异,本文以 MySQL 为例讲解。
下面是创建函数的语法:
CREATE FUNCTION 函数名(参数名1 数据类型, 参数名2 数据类型, ...) RETURNS 返回值数据类型 [DETERMINISTIC] -- 可选:表示函数返回结果固定(相同输入必返回相同输出) BEGIN -- 函数体:核心逻辑(变量定义、条件判断、计算等) RETURN 返回值; END;
示例1:创建计算用户年龄的函数
-- 创建函数 get_user_age
> CREATE FUNCTION get_user_age(birthday DATE)
RETURNS INT
DETERMINISTIC
BEGIN
-- 定义变量存储年龄
DECLARE user_age INT;
-- 计算年龄:当前年份 - 生日年份,若未到生日则减1
SET user_age = YEAR(CURDATE()) - YEAR(birthday);
IF MONTH(CURDATE()) < MONTH(birthday) OR
(MONTH(CURDATE()) = MONTH(birthday) AND DAY(CURDATE()) < DAY(birthday)) THEN
SET user_age = user_age - 1;
END IF;
-- 返回计算结果
RETURN user_age;
END
0 row(s) modified.
-- 调用函数
> SELECT get_user_age('2020-10-02') AS age
age|
---+
5|
1 row(s) fetched.示例 2:创建计算商品折扣价的函数,计算折扣后价格(保留 2 位小数)。
-- 创建折扣计算函数 > CREATE FUNCTION get_discount_price(original_price DECIMAL(10,2), discount_rate DECIMAL(3,2)) RETURNS DECIMAL(10,2) DETERMINISTIC BEGIN -- 处理异常:折扣率不能小于0或大于1 IF discount_rate < 0 OR discount_rate > 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '折扣率必须在0-1之间'; END IF; -- 计算折扣价并返回 RETURN ROUND(original_price * discount_rate, 2); END 0 row(s) modified. -- 调用函数 > SELECT get_discount_price(1278.45, 0.8) AS discount_price discount_price| --------------+ 1022.76| 1 row(s) fetched.
这里以 MySQL 为例,在 MySQL 中,可以使用 SHOW CREATE FUNCTION 命令查看函数的定义:
SHOW CREATE FUNCTION get_user_age;
例如,查看 get_user_age 函数的定义,在 MySQL 客户端中执行命令
mysql> SHOW CREATE FUNCTION get_user_age \G *************************** 1. row *************************** Function: get_user_age sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION Create Function: CREATE DEFINER=`root`@`%` FUNCTION `get_user_age`(birthday DATE) RETURNS int DETERMINISTIC BEGIN -- 定义变量存储年龄 DECLARE user_age INT; -- 计算年龄:当前年份 - 生日年份,若未到生日则减1 SET user_age = YEAR(CURDATE()) - YEAR(birthday); IF MONTH(CURDATE()) < MONTH(birthday) OR (MONTH(CURDATE()) = MONTH(birthday) AND DAY(CURDATE()) < DAY(birthday)) THEN SET user_age = user_age - 1; END IF; -- 返回计算结果 RETURN user_age; END character_set_client: utf8mb4 collation_connection: utf8mb4_0900_ai_ci Database Collation: utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
在 MySQL 中,可以使用 DROP FUNCTION 语句删除已经存在的函数。例如:
-- 删除 get_user_age 函数 > DROP FUNCTION IF EXISTS get_user_age 0 row(s) modified.
注意事项:
创建函数需具备CREATE ROUTINE权限;
函数体内避免使用SELECT *等返回结果集的语句,自定义函数仅能返回单个值;
尽量保证函数是 “纯函数”(相同输入返回相同输出),便于数据库优化。