
mysql 8.0 严格校验 date 值,不再允许对 date 字段直接使用 `'2020-02%'` 这类含通配符的字符串比较;应改用 `date_format()`、`year()`/`month()` 函数或范围查询实现按年月模糊筛选。
在 MySQL 5.7 中,部分宽松模式下允许将字符串 '2020-02%' 隐式转换为 DATE 进行比较(尽管语义不严谨),但 MySQL 8.0 默认启用严格 SQL 模式(STRICT_TRANS_TABLES),明确拒绝此类非法日期字面量,抛出 Incorrect DATE value: '2020-02%' 错误。
根本原因:last_date 是 DATE 类型字段,而 '2020-02%' 是无效的日期字面量——% 不是合法日期字符,MySQL 8.0 不再尝试模糊匹配或截断解析。
✅ 推荐解决方案(兼顾性能与可读性):
1. 使用 DATE_FORMAT() 提取年月比较(适用于按“年-月”前缀筛选)
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';✅ 语义清晰:等价于“2020年2月及之后的所有日期” ⚠️ 注意:该写法无法利用 last_date 上的索引(函数包裹导致索引失效),大数据量时需谨慎。
2. 改用范围查询(最优性能,强烈推荐)
-- 查询 2020-02-01 起的所有记录(含当月及之后) AND cssd.last_date >= '2020-02-01' -- 若需精确匹配“2020年2月及以后”,可结合日期边界: AND cssd.last_date >= '2020-02-01'
✅ 完全走索引,执行高效
✅ 符合 SQL 标准,兼容所有 MySQL 版本
? 小技巧:动态生成边界值(如 STR_TO_DATE('2020-02', '%Y-%m'))可提升灵活性。
3. 拆分年月字段(适合高频按月查询场景)
若业务频繁按年、月过滤,可在表中增加生成列并建索引:
ALTER TABLE combined_sales_service_data ADD COLUMN last_year_month CHAR(7) GENERATED ALWAYS AS (DATE_FORMAT(last_date, '%Y-%m')) STORED, ADD INDEX idx_last_ym (last_year_month);
后续查询即可安全使用:
AND cssd.last_year_month >= '2020-02'
❌ 不推荐方案:
- 启用 ALLOW_INVALID_DATES(已弃用且不解决根本问题)
- 使用 CAST(cssd.last_date AS CHAR) LIKE '2020-02%'(隐式转换不可靠,且同样无法索引)
总结:MySQL 8.0 的严格类型校验是正确行为。应摒弃对 DATE 字段使用字符串通配符的旧习惯,优先采用范围查询(>= 'YYYY-MM-DD')保障性能与兼容性;若需灵活年月匹配,辅以 DATE_FORMAT() 或冗余生成列优化。










