1. MySQL函数基础与核心价值
刚接触MySQL那会儿,我最头疼的就是记不住各种函数用法,直到有次处理用户手机号脱敏需求时,发现用SUBSTRING()和CONCAT()配合,三行代码就解决了问题——这才意识到函数就是SQL世界的瑞士军刀。作为关系型数据库的标配功能,MySQL函数能让我们用更少的代码完成数据清洗、计算和转换,把原本需要应用程序处理的逻辑下推到数据库层执行。
函数在MySQL中分为两大类:单行函数(对每行数据独立计算)和聚合函数(对多行数据汇总计算)。实际工作中最常见的应用场景包括:
- 数据清洗(去除空格、大小写转换)
- 业务逻辑计算(日期差、金额格式化)
- 动态条件生成(CASE WHEN条件分支)
- 数据脱敏(部分信息隐藏)
重要提示:虽然函数能简化操作,但过度使用会导致SQL可读性下降。建议复杂函数配合注释使用,且避免在WHERE条件中对字段使用函数(会导致索引失效)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 字符串处理函数实战精要
2.1 基础字符串操作
上周排查一个用户投诉时,发现系统把"O'Reilly"存成了"O'Reilly",这就是没用好CONCAT()和ESCAPE的典型例子。字符串函数里这几个最常用:
sql复制-- 连接字符串(注意NULL处理)
SELECT CONCAT('MySQL', ' ', 'Functions') AS result; -- 'MySQL Functions'
SELECT CONCAT_WS('-', '2023', '07', '15') AS date_str; -- 用指定分隔符连接
-- 大小写转换(用户输入标准化)
SELECT LOWER('MySQL'), UPPER('mysql');
-- 去空格(表单数据清洗)
SELECT TRIM(' hello '), LTRIM(' hello'), RTRIM('hello ');
2.2 高级字符串处理技巧
去年做电商项目时,商品SKU的解析就用到了SUBSTRING_INDEX,比用程序处理快3倍:
sql复制-- 提取特定部分(如解析URL路径)
SELECT
SUBSTRING('https://example.com/path', 9) AS domain,
SUBSTRING_INDEX('user@example.com', '@', -1) AS email_domain;
-- 模式替换(数据脱敏经典方案)
SELECT
INSERT('13812345678', 4, 4, '****') AS phone_mask,
REPLACE('信用卡号: 1234', '1234', '****') AS card_mask;
避坑指南:CHAR_LENGTH()和LENGTH()的区别经常被忽视。前者按字符数计算(中文算1个),后者按字节计算(UTF-8中文占3字节)。用户名字段校验时用错会导致严重BUG。
3. 数值计算与格式化函数详解
3.1 基础数学运算函数
财务系统开发时,ROUND()的坑我踩过两次——银行家舍入规则和普通四舍五入完全不同:
sql复制-- 四舍五入(注意第二个参数是小数位数)
SELECT ROUND(3.1415, 2), ROUND(3.1415); -- 3.14, 3
-- 银行家舍入法(IEEE标准)
SELECT ROUND(2.5), ROUND(3.5); -- 2, 4
-- 取整函数对比
SELECT
CEIL(3.2), -- 向上取整 → 4
FLOOR(3.8), -- 向下取整 → 3
TRUNCATE(3.1415, 2); -- 直接截断 → 3.14
3.2 数值格式化与类型转换
做跨国电商时,发现不同地区的金额显示格式差异巨大:
sql复制-- 金额格式化(德国格式示例)
SELECT FORMAT(1234567.89, 2, 'de_DE'); -- 1.234.567,89
-- 类型转换(处理混合类型比较)
SELECT
CAST('123' AS SIGNED) AS str_to_int,
CONVERT(3.1415, DECIMAL(10,2)) AS float_to_decimal;
经验之谈:DECIMAL类型计算时,建议先用CAST统一精度,避免隐式转换导致精度丢失。比如CAST(amount AS DECIMAL(20,6))后再做除法运算。
4. 日期时间函数核心应用
4.1 日期获取与计算
会员系统做续费提醒时,日期函数组合节省了80%的代码量:
sql复制-- 当前时间获取(注意时区问题)
SELECT NOW(), CURDATE(), CURTIME();
-- 日期加减(支持INTERVAL表达式)
SELECT
DATE_ADD(NOW(), INTERVAL 7 DAY) AS next_week,
DATE_SUB('2023-12-31', INTERVAL 3 MONTH) AS prev_quarter;
-- 日期差计算(两种模式)
SELECT
DATEDIFF('2023-12-31', '2023-01-01') AS day_diff,
TIMESTAMPDIFF(MONTH, '2023-01-15', '2023-12-20') AS month_diff;
4.2 日期格式化与解析
报表系统对接时,DATE_FORMAT的格式字符串让我背了好久:
sql复制-- 日期格式化(支持各种语言环境)
SELECT
DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS std_format,
DATE_FORMAT(NOW(), '%W, %M %e, %Y') AS en_format;
-- 字符串转日期(严格模式要注意)
SELECT
STR_TO_DATE('2023/07/15', '%Y/%m/%d') AS parsed_date,
STR_TO_DATE('15-07-2023', '%d-%m-%Y') AS euro_date;
关键细节:MySQL5.7+的严格模式会拒绝非法日期(如'2023-02-30'),旧版本会返回NULL或转换为'0000-00-00'。生产环境务必先做校验。
5. 条件判断与流程控制函数
5.1 CASE WHEN表达式
用户分级统计报表中,CASE WHEN比多次查询效率高10倍不止:
sql复制-- 简单CASE表达式
SELECT
user_level,
CASE user_level
WHEN 1 THEN '普通'
WHEN 2 THEN '白银'
WHEN 3 THEN '黄金'
ELSE '未知'
END AS level_name
FROM users;
-- 搜索式CASE(更灵活)
SELECT
order_amount,
CASE
WHEN order_amount > 1000 THEN '大额'
WHEN order_amount > 500 THEN '中额'
ELSE '小额'
END AS amount_type
FROM orders;
5.2 逻辑判断函数
权限系统里IFNULL和COALESCE的差异曾导致严重漏洞:
sql复制-- 空值处理对比
SELECT
IFNULL(NULL, 'default'), -- 第一个参数为NULL时返回第二个
COALESCE(NULL, NULL, 'last'); -- 返回第一个非NULL值
-- 三目运算式IF函数
SELECT
IF(score >= 60, '及格', '不及格') AS result,
IF(COUNT(*) > 0, '有数据', '无数据') AS has_data;
安全警告:WHERE条件中使用CASE WHEN时要特别注意索引使用情况,复杂的CASE表达式可能导致全表扫描。
6. 窗口函数进阶技巧(MySQL8.0+)
6.1 排名与分页优化
最近用ROW_NUMBER()改造旧分页查询,性能从2秒提升到200ms:
sql复制-- 经典排名场景
SELECT
product_id,
sales,
ROW_NUMBER() OVER(ORDER BY sales DESC) AS rank1,
DENSE_RANK() OVER(ORDER BY sales DESC) AS rank2,
PERCENT_RANK() OVER(ORDER BY sales DESC) AS pct_rank
FROM products;
-- 高效分页方案(对比LIMIT offset方案)
WITH ranked_data AS (
SELECT *, ROW_NUMBER() OVER() AS rn FROM large_table
)
SELECT * FROM ranked_data WHERE rn BETWEEN 1001 AND 1020;
6.2 滑动窗口分析
做销售趋势分析时,窗口帧定义让代码简洁多了:
sql复制-- 移动平均计算
SELECT
sale_date,
amount,
AVG(amount) OVER(ORDER BY sale_date ROWS 2 PRECEDING) AS moving_avg
FROM daily_sales;
-- 累计求和
SELECT
month,
revenue,
SUM(revenue) OVER(ORDER BY month) AS ytd_revenue
FROM monthly_report;
性能提示:窗口函数会创建临时表,大数据集使用时建议配合适当的PARTITION BY子句,避免单个大窗口的内存问题。
7. 高级函数组合应用案例
7.1 JSON数据处理(MySQL5.7+)
去年重构用户属性存储时,JSON函数帮了大忙:
sql复制-- 提取JSON字段
SELECT
JSON_EXTRACT(user_info, '$.address.city') AS city,
user_info->>'$.address.city' AS city_shortcut
FROM users;
-- 动态更新JSON
UPDATE users
SET user_info = JSON_SET(user_info, '$.preferences.theme', 'dark')
WHERE user_id = 1001;
-- 生成JSON数组
SELECT
department_id,
JSON_ARRAYAGG(employee_name) AS team_members
FROM employees
GROUP BY department_id;
7.2 全文检索函数
商品搜索功能优化时,MATCH AGAINST比LIKE快50倍:
sql复制-- 创建全文索引(前置步骤)
ALTER TABLE products ADD FULLTEXT INDEX ft_index(name, description);
-- 基础搜索(自然语言模式)
SELECT * FROM products
WHERE MATCH(name, description) AGAINST('手机 防水' IN NATURAL LANGUAGE MODE);
-- 布尔模式高级搜索
SELECT * FROM products
WHERE MATCH(name, description) AGAINST('+华为 -手机' IN BOOLEAN MODE);
8. 函数性能优化与避坑指南
8.1 索引使用禁忌
曾有个慢查询折磨了我们两周,最后发现是DATE_FORMAT惹的祸:
sql复制-- 反例:索引失效写法
SELECT * FROM orders
WHERE DATE_FORMAT(create_time, '%Y-%m') = '2023-07';
-- 正例:可走索引的写法
SELECT * FROM orders
WHERE create_time >= '2023-07-01' AND create_time < '2023-08-01';
8.2 存储函数慎用
自定义函数在触发器里使用时,一个递归调用差点让数据库崩溃:
sql复制-- 可能导致性能问题的写法
CREATE FUNCTION calc_bonus(emp_id INT) RETURNS DECIMAL(10,2)
BEGIN
DECLARE bonus DECIMAL(10,2);
-- 复杂计算逻辑
RETURN bonus;
END;
-- 更好的方案:用应用程序计算或简单SQL函数
8.3 字符集陷阱
迁移数据库时,GROUP_CONCAT突然截断数据,原来是字符集问题:
sql复制-- 安全使用GROUP_CONCAT
SET SESSION group_concat_max_len = 1000000;
SELECT GROUP_CONCAT(product_name SEPARATOR '|')
FROM products
GROUP BY category_id;
9. 最新版本函数特性(MySQL8.0+)
9.1 通用表表达式(CTE)
递归CTE处理树形数据比多次查询优雅多了:
sql复制-- 组织架构层级查询
WITH RECURSIVE org_tree AS (
SELECT id, name, parent_id, 1 AS level
FROM departments WHERE parent_id IS NULL
UNION ALL
SELECT d.id, d.name, d.parent_id, ot.level + 1
FROM departments d
JOIN org_tree ot ON d.parent_id = ot.id
)
SELECT * FROM org_tree ORDER BY level, id;
9.2 窗口函数增强
新增的NTH_VALUE()让中间值分析更简单:
sql复制-- 获取销售亚军信息
SELECT
product_id,
sales,
NTH_VALUE(product_id, 2) OVER(ORDER BY sales DESC) AS second_place
FROM products;
10. 实用函数速查手册
10.1 常用函数对照表
| 场景 | 推荐函数 | 替代方案 |
|---|---|---|
| 空值处理 | COALESCE() | IFNULL()/ISNULL() |
| 复杂条件判断 | CASE WHEN | IF()/ELT() |
| 字符串拼接 | CONCAT_WS() | CONCAT()/+运算符 |
| 日期格式化 | DATE_FORMAT() | STR_TO_DATE() |
| 分页查询 | ROW_NUMBER() OVER() | LIMIT offset |
| JSON处理 | JSON_EXTRACT()/->> | 应用层解析 |
10.2 版本兼容性备忘
- MySQL 5.7:支持JSON函数、全文检索增强
- MySQL 8.0:窗口函数、CTE、原子DDL
- MariaDB 10.2:兼容大部分MySQL函数,但有细微差异
最后分享一个真实案例:有次凌晨处理数据异常,发现是CONVERT_TZ()没考虑夏令时导致的。时间函数一定要用生产数据实测边界条件,文档里的例子不一定覆盖所有场景。
