作为数据库开发中最常用的功能之一,日期处理在业务系统中无处不在。从简单的记录创建时间到复杂的时段统计分析,掌握MySQL日期函数是每个开发者的必备技能。今天我将结合15年数据库开发经验,带你深入理解这些函数的实际应用场景。
获取当前日期是日常开发中最基础的操作:
sql复制-- 获取当前日期(年月日)
SELECT CURRENT_DATE();
-- 输出示例:2023-08-15
-- 获取当前时间(时分秒)
SELECT CURRENT_TIME();
-- 输出示例:14:30:45
-- 获取完整时间戳(年月日 时分秒)
SELECT CURRENT_TIMESTAMP();
-- 输出示例:2023-08-15 14:30:45
注意:
NOW()函数与CURRENT_TIMESTAMP()功能相同,但在某些SQL模式下有微秒级精度差异。生产环境中建议统一使用其中一种,避免混用。
实际业务中经常需要对日期进行加减运算:
sql复制-- 日期加法(10天后)
SELECT DATE_ADD('2023-08-15', INTERVAL 10 DAY);
-- 输出:2023-08-25
-- 日期减法(2天前)
SELECT DATE_SUB('2023-08-15', INTERVAL 2 DAY);
-- 输出:2023-08-13
日期差值计算在统计业务中特别有用:
sql复制-- 计算两个日期相差天数
SELECT DATEDIFF('2023-08-15', '2023-07-01');
-- 输出:45
经验分享:INTERVAL关键字支持多种时间单位:
- YEAR/MONTH/DAY
- HOUR/MINUTE/SECOND
- WEEK/QUARTER等
灵活组合这些单位可以处理各种复杂的时间计算需求。
sql复制CREATE TABLE user_birthdays (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(50) NOT NULL,
birthday DATE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 插入数据示例
INSERT INTO user_birthdays (user_name, birthday)
VALUES ('张三', '1990-05-20'),
('李四', CURRENT_DATE());
避坑指南:DATE类型只存储日期部分,如果误传DATETIME值,MySQL会自动截取日期部分并产生警告。建议使用STR_TO_DATE()函数显式转换。
sql复制-- 创建消息表
CREATE TABLE messages (
id INT PRIMARY KEY AUTO_INCREMENT,
content TEXT NOT NULL,
send_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_read BOOLEAN DEFAULT FALSE
);
-- 查询最近2分钟内的未读消息
SELECT id, content
FROM messages
WHERE send_time > DATE_SUB(NOW(), INTERVAL 2 MINUTE)
AND is_read = FALSE;
这个查询利用了日期函数实现了一个常见的消息时效性检查功能。在即时通讯、通知系统等场景非常实用。
字符串处理是数据库操作的另一个核心领域。正确使用字符串函数可以显著减少应用层代码量,提高查询效率。
sql复制-- 检测字段字符集
SELECT CHARSET(ename) FROM emp;
-- 输出示例:utf8mb4
注意:MySQL 8.0默认使用utf8mb4字符集,完整支持emoji等4字节字符。旧版的utf8只支持3字节字符。
sql复制-- 基本连接
SELECT CONCAT('Hello', ' ', 'World');
-- 输出:Hello World
-- 带NULL值的连接
SELECT CONCAT('Hello', NULL, 'World');
-- 输出:NULL
经验技巧:CONCAT_WS()函数可以指定分隔符并自动跳过NULL值,更适合实际业务场景。
sql复制-- 转大写
SELECT UCASE('MySQL');
-- 输出:MYSQL
-- 转小写
SELECT LCASE('MySQL');
-- 输出:mysql
sql复制-- 从左截取
SELECT LEFT('MySQL', 2);
-- 输出:My
-- 从右截取
SELECT RIGHT('MySQL', 3);
-- 输出:SQL
-- 任意位置截取
SELECT SUBSTRING('MySQL', 2, 3);
-- 输出:ySQ
sql复制-- 字节长度(中文通常占3字节)
SELECT LENGTH('中国');
-- 输出:6
-- 字符长度
SELECT CHAR_LENGTH('中国');
-- 输出:2
关键区别:LENGTH()返回字节数,CHAR_LENGTH()返回字符数。处理多字节字符时务必注意!
sql复制-- 简单替换
SELECT REPLACE('MySQL', 'SQL', 'Database');
-- 输出:MyDatabase
-- 表字段替换
SELECT REPLACE(ename, 'S', '上海') FROM emp;
sql复制SELECT CONCAT(
name, '的',
'语文', chinese, '分,',
'数学', math, '分,',
'英语', english, '分'
) AS report
FROM exam_result;
sql复制-- 首字母小写
SELECT CONCAT(
LCASE(SUBSTRING(ename, 1, 1)),
SUBSTRING(ename, 2)
) FROM emp;
-- 姓名脱敏处理
SELECT CONCAT(
LEFT(ename, 1),
REPEAT('*', CHAR_LENGTH(ename)-1)
) FROM emp;
sql复制-- 标准格式化
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
-- 输出:2023-08-15 15:30:45
-- 中文友好格式
SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H时%i分');
-- 输出:2023年08月15日 15时30分
sql复制-- 字符串转日期
SELECT STR_TO_DATE('2023-08-15', '%Y-%m-%d');
-- 输出:2023-08-15
-- 日期转字符串
SELECT DATE_FORMAT(CURRENT_DATE(), '%W, %M %d %Y');
-- 输出:Tuesday, August 15 2023
在WHERE条件中对日期字段使用函数会导致索引失效:
sql复制-- 不推荐(无法使用索引)
SELECT * FROM orders WHERE DATE_FORMAT(create_time, '%Y-%m') = '2023-08';
-- 推荐(可以使用索引)
SELECT * FROM orders
WHERE create_time BETWEEN '2023-08-01' AND '2023-08-31';
大文本字段的字符串操作尽量在应用层处理,避免数据库性能瓶颈。
考虑使用生成列(GENERATED COLUMN)存储常用计算结果的格式化版本:
sql复制ALTER TABLE messages ADD COLUMN send_date DATE
GENERATED ALWAYS AS (DATE(send_time)) STORED;
sql复制-- 查看当前时区设置
SELECT @@global.time_zone, @@session.time_zone;
-- 会话级时区设置
SET time_zone = '+08:00';
生产环境建议:在MySQL配置文件中统一设置时区,避免应用层出现时间不一致问题。
sql复制-- 强制转换字符集
SELECT CONVERT(ename USING gbk) FROM emp;
-- 连接字符集设置
SET NAMES 'utf8mb4';
sql复制-- NULL值默认处理
SELECT IFNULL(NULL, '默认值');
-- 输出:默认值
-- 多字段NULL处理
SELECT COALESCE(NULL, NULL, '第三个值', '第四个值');
-- 输出:第三个值
在实际项目中,我经常遇到日期和字符串处理相关的性能问题。一个典型的案例是:某电商平台的订单报表查询最初需要30秒才能返回结果,经过优化日期查询条件和重构字符串处理逻辑后,性能提升到0.5秒内。关键点在于: