STR_TO_DATE 返回 NULL 的根本原因是格式字符串与输入字符串未严格匹配,包括空格、分隔符、位数(如 %m 要求两位)、年份格式(%y 两位 vs %Y 四位)等必须完全一致,且不支持自动清洗非标准字符。

STR_TO_DATE 为什么总返回 NULL?
STR_TO_DATE 返回 NULL 的根本原因不是函数坏了,而是格式字符串和输入字符串不严格匹配。MySQL 会逐字符比对,哪怕多一个空格、少一个分隔符、年份位数不对(比如用 %Y 解析 "21"),都会失败。
常见错误现象:STR_TO_DATE('2023-05-1', '%Y-%m-%d') 返回 NULL(因为 '05' 和 '5' 不等长);STR_TO_DATE('01/02/2023', '%Y-%m-%d') 也返回 NULL(格式完全错位)。
- 必须确保输入字符串中每个非字面量部分(如数字、斜杠)都与格式符一一对应
- 月份、日期不足两位时,不能强制用
%m或%d—— 改用%c(1–12)或%e(1–31) - 年份要分清:
%y是两位(00–99),%Y是四位;解析 "23" 必须用%y,否则失败
处理带中文或混合符号的日期字符串
比如 '2023年05月01日'、'2023/5/1 上午10:30' 这类非标准字符串,不能靠改格式符硬套,得先清洗或拆分。
STR_TO_DATE 本身不支持正则替换,所以得组合使用函数:
- 用
REPLACE()去掉中文单位:STR_TO_DATE(REPLACE(REPLACE(REPLACE('2023年05月01日', '年', '-'), '月', '-'), '日', ''), '%Y-%m-%d') - 含时间且有“上午/下午”时,先转 24 小时制:
REPLACE(REPLACE('2023/5/1 上午10:30', '上午', ''), '下午', '12')不够安全,建议用CASE+SUBSTRING判断并加偏移 - 注意:STR_TO_DATE 对时间部分也敏感,
%H(00–23)和%h(01–12)不能混用,搭配%p才能识别 AM/PM
在 INSERT 或 UPDATE 中安全使用 STR_TO_DATE
直接把 STR_TO_DATE() 写进 INSERT 语句里,一旦某条记录格式异常,整条语句可能因类型转换失败而报错(尤其开启严格模式时)。
- 先用
SELECT STR_TO_DATE(...)单独测试一批样本,确认无NULL再批量写入 - 插入前加判断:
IFNULL(STR_TO_DATE(@raw_date, '%Y/%c/%e'), '0000-00-00'),避免阻断流程(但要注意 '0000-00-00' 在严格模式下也可能被拒绝) - 如果源数据来自 CSV 或日志,建议在加载前用脚本预处理成统一格式,而不是全靠 SQL 转换 —— STR_TO_DATE 不是万能清洗工具
替代方案:什么时候该放弃 STR_TO_DATE?
当遇到以下情况,硬套 STR_TO_DATE 效率低、维护难,不如换思路:
- 同一字段混杂多种格式(如有的写 "2023-01-01",有的写 "01/01/2023",还有的写 "Jan 1, 2023")—— 此时应拆成多个
CASE WHEN分支,各自配格式符 - 需要毫秒级精度或时区信息 —— STR_TO_DATE 不支持
%f(微秒)以外的精度,也不解析时区缩写(如 "CST"),这类需求得靠应用层处理 - MySQL 版本 NO_ZERO_DATE 模式时,
STR_TO_DATE('abc', ...)可能触发警告甚至中断,比预期更脆弱
真正麻烦的从来不是函数怎么写,而是原始数据到底有多“脏”——格式不一致、缺失字段、非法字符、编码乱码,这些都得在调用 STR_TO_DATE 前搞定。

















