
mysql 8.0严格校验date类型,不支持在where子句中对date字段直接使用字符串通配符(如'2020-02%'),需改用date_format、year/month函数或范围查询实现按年月模糊筛选。
在 MySQL 8.0 中,DATE 类型字段(如 last_date)不能直接与带通配符的字符串(如 '2020-02%')进行比较,因为 MySQL 会尝试将该字符串强制转换为合法日期,而 '2020-02%' 不是有效日期字面量,从而触发错误 Incorrect DATE value。这与 MySQL 5.7 的宽松解析行为不同,是 8.0 强化数据完整性的体现。
✅ 推荐解决方案:使用 DATE_FORMAT() 提取年月进行字符串比较
适用于“获取 2020 年 2 月及之后所有日期”的场景:
SELECT
'01',
2103,
cssd._campaign_id,
cssd.first,
cssd.last,
cssd.street,
cssd.city,
cssd.state,
cssd.zip,
cssd.customer_id,
cssd.vin,
cssd.email,
cssd.phone,
cssd.phone2,
cssd.phonecell
FROM combined_sales_service_data cssd
WHERE cssd._campaign_id = 25
AND DATE_FORMAT(cssd.last_date, '%Y-%m') >= '2020-02';? 说明:
- DATE_FORMAT(last_date, '%Y-%m') 将日期转为 'YYYY-MM' 格式字符串(如 '2020-02'),再与 '2020-02' 进行字典序比较,逻辑等价于“年月不小于 2020 年 2 月”。
- ✅ 兼容 MySQL 8.0+,无需修改 SQL 模式;
- ⚠️ 注意:该写法无法利用 last_date 上的索引(因对列应用了函数),若表数据量大且性能敏感,建议改用范围查询(见下文)。
✅ 更优性能方案:使用日期范围(推荐用于大数据量)
避免函数包裹,让优化器可走索引:
-- 查询 2020-02-01 起的所有记录(含当月及之后) AND cssd.last_date >= '2020-02-01'
若需精确到“2020年2月及以后”,但起始日不固定(如动态传参 '2020-02'),可用如下安全计算:
-- 动态生成起始日期:'2020-02' → '2020-02-01'
AND cssd.last_date >= STR_TO_DATE('2020-02', '%Y-%m')? 其他可行方式(按场景选择):
- 按年份+月份分别判断:YEAR(last_date) > 2020 OR (YEAR(last_date) = 2020 AND MONTH(last_date) >= 2)
- 使用 LEFT() + CAST(不推荐,冗余且不可索引):LEFT(CAST(last_date AS CHAR), 7) >= '2020-02'
⚠️ 重要提醒:
- ❌ 禁用 ALLOW_INVALID_DATES 模式(已弃用且破坏数据一致性);
- ❌ 避免 CONVERT(last_date, CHAR) 或隐式类型转换,行为不可控;
- ✅ 始终优先考虑索引友好写法——范围查询 > 函数提取 > 字符串模糊匹配。
总结:在 MySQL 8.0 中处理日期“模糊匹配”,应放弃通配符思维,转向语义明确的日期函数或范围表达式。DATE_FORMAT(..., '%Y-%m') 是最直观的替代方案,而 STR_TO_DATE() + 范围查询则是兼顾可读性与性能的最佳实践。










