str_to_date函数参数顺序不可颠倒,首参为待转字符串、次参为格式模板;格式须严格逐字符匹配,错配静默返回null;需用%c/%e处理无前导零、%y/%y区分年份位数,中文字符须字字对应,推荐trim清洗和coalesce兜底。

STR_TO_DATE 用法:参数顺序不能颠倒
STR_TO_DATE 的第一个参数是待转换的字符串,第二个参数是格式模板,顺序反了会返回 NULL。比如把 "2023-10-05" 转成日期,得写成 STR_TO_DATE('2023-10-05', '%Y-%m-%d'),而不是反过来。
常见错误是照着 DATE_FORMAT 的习惯写反了——后者是先日期后模板,而 STR_TO_DATE 是先字符串后模板,记混就全错。
- 模板中
%Y表示 4 位年份,%y是 2 位;用错会导致年份解析异常(如'23'配%Y得到0023) - 月份用
%m(补零)或%c(不补零),'1/5/2023'必须用'%c/%e/%Y',不能硬套'%m/%d/%Y' - 中文日期如
"2023年10月5日"要写成'%Y年%m月%d日',汉字部分必须字字匹配,少一个字就失败
NULL 返回值:不是语法错,而是格式不匹配
执行 STR_TO_DATE 后得到 NULL,大概率不是函数写错了,而是输入字符串和格式模板对不上。MySQL 不报错,只静默返回 NULL,容易误判为数据为空。
调试时建议先用 SELECT 单独测试一两条典型数据:
SELECT date_str, STR_TO_DATE(date_str, '%Y/%m/%d') AS parsed, LENGTH(date_str) AS len FROM (SELECT '2023/10/05' AS date_str UNION SELECT '2023-10-05') t;
这样能快速看出哪些值因格式不符被丢弃。
- 空格、不可见字符(如 BOM、全角空格)会导致匹配失败,可用
TRIM()或REPLACE()清洗 - 模板里多写了字符(如
'%Y-%m-%d '结尾带空格),但字符串没空格,就匹配不上 - 日期本身非法(如
'2023-02-30')也会返回NULL,不是格式问题,是逻辑无效
在 INSERT / UPDATE 中直接使用需注意类型兼容性
往 DATE 或 DATETIME 字段插入时,STR_TO_DATE 的结果可直接用,但要注意目标字段精度。比如源字符串是 '2023-10-05 14:30:00',模板用了 '%Y-%m-%d',结果只有日期部分,时间被截断为 '00:00:00'。
- 目标字段是
DATETIME但只传了日期模板,会补上默认时间,不是报错 - 批量导入时,若某行解析失败(返回
NULL),而目标字段设了NOT NULL且无默认值,整条 INSERT 就会失败 - 安全做法是配合
COALESCE提供兜底值:COALESCE(STR_TO_DATE(str_date, '%Y-%m-%d'), '1970-01-01')
替代方案:什么时候不该用 STR_TO_DATE
如果原始数据格式统一且符合标准 ISO 格式(如 '2023-10-05' 或 '2023-10-05 14:30:00'),直接用 CAST(str AS DATE) 或 DATE(str) 更快,也更简洁。这些函数内部做了优化,不依赖模板解析。
-
STR_TO_DATE是通用解法,但性能略低;纯标准格式下没必要绕一圈 - 从 JSON 或 CSV 导入时,如果列定义为
DATE类型,MySQL 通常自动尝试转换,显式调用STR_TO_DATE反而可能干扰隐式行为 - 跨库迁移时注意:PostgreSQL 用
TO_DATE(),SQLite 用strftime(),函数名和模板语法都不同,别直接复制粘贴
真正需要 STR_TO_DATE 的场景,是那些非标准、带分隔符、含文字或本地化格式的字符串——比如 Excel 导出的 "Oct 5, 2023" 或日志里的 "05/Oct/2023:14:30:00"。这种时候,模板细节就是成败关键。











