varchar类型日期字段的min/max按字典序比较不可靠,可能返回非法值如'2023-13-01';必须先确认字段类型,再用str_to_date或::date转换为日期类型后聚合,否则结果不反映真实时间顺序。

字符型日期字段的MIN/MAX结果不可信
直接对 VARCHAR 类型的“日期字符串”用 MIN() 或 MAX(),得到的不是最早/最晚时间,而是字典序最小/最大的字符串。比如 '2023-13-01'、'2023-01-00' 这类非法值,只要字典序靠前,就会被当作“最小日期”返回——它甚至不是合法日期。
怎么确认字段是不是假日期真字符串
别看内容像日期,要看实际类型:
- 运行
DESCRIBE your_table或SHOW COLUMNS FROM your_table LIKE 'date_col' - 如果类型是
VARCHAR、CHAR或TEXT,哪怕值全是'2023-01-01'格式,MIN()也只做字符串比较 - 临时验证:执行
SELECT date_col FROM your_table WHERE STR_TO_DATE(date_col, '%Y-%m-%d') IS NULL LIMIT 5(MySQL),查出不能转成真实日期的脏数据
临时修复:强制转日期再聚合
不改表结构也能拿到正确极值,但必须绕过字符串比较:
- MySQL:
SELECT MIN(STR_TO_DATE(date_col, '%Y-%m-%d')) FROM t - PostgreSQL:
SELECT MIN(date_col::DATE) FROM t(前提是格式严格)或SELECT MIN(TO_DATE(date_col, 'YYYY-MM-DD')) FROM t - 注意:
STR_TO_DATE()遇到非法格式返回NULL,会被MIN()自动跳过——所以先清理脏数据比硬扛更重要
真正容易被忽略的是时区和精度陷阱
就算字段已是 DATETIME 类型,MIN() 也可能不准:
- MySQL 5.6.4 之前默认秒级精度,
'2023-01-01 10:00:00.123'存进去只剩'2023-01-01 10:00:00',同一秒内多条记录无法区分先后 - 字段是
TIMESTAMP但客户端时区不一致,MIN()返回值会随连接时区参数动态转换,不是固定时间点 -
SHOW CREATE TABLE中看到DATETIME(3)才表示毫秒级;没括号就是秒级,别假设它能分辨毫秒差异











