date_format是mysql特有函数,需两个参数:日期值(date/datetime/合法字符串)和格式模板(如'%y-%m-%d'),传null返回null;where中使用会导致索引失效,应改用范围查询。

DATE_FORMAT函数的基本用法和必需参数
DATE_FORMAT 是 MySQL 特有的日期格式化函数,不能直接在 PostgreSQL、SQL Server 或 SQLite 中使用。它接收两个参数:第一个是日期值(可以是 DATE、DATETIME 或合法字符串),第二个是格式化模板字符串。模板中必须用特定占位符(如 %Y、%m)表示年月日等部分,普通字符需原样保留或加转义。
常见错误是把模板写成 'YYYY-MM-DD' —— 这会原样输出字面量,不是变量替换。正确写法是 '%Y-%m-%d'。
-
DATE_FORMAT(NOW(), '%Y-%m-%d')→2024-05-21 -
DATE_FORMAT('2023-12-25', '%W, %M %e, %Y')→Monday, December 25, 2023 - 传入
NULL时返回NULL,不会报错,但容易被忽略导致前端显示异常
常用格式符含义与易混淆点
不同占位符对前导零、大小写、本地化敏感度差异很大。比如 %y(两位年份)和 %Y(四位年份)混用会导致 2023 年显示为 23;%m(补零月)和 %c(无补零月)在排序或拼接路径时可能引发隐式类型转换问题。
-
%d:补零日(01–31),%e:无补零日(1–31) -
%H:24 小时制小时(00–23),%h或%I:12 小时制(01–12),注意大小写敏感 -
%p只在搭配%h时有效,单独用会输出空字符串 -
%j是一年中的第几天(001–366),不是星期几 —— 常被误当成%w(周日=0)或%W(全名)
在 WHERE 子句中误用 DATE_FORMAT 的性能陷阱
用 DATE_FORMAT(create_time, '%Y-%m') = '2024-05' 做查询条件,会导致 create_time 字段无法走索引(函数包裹列),全表扫描风险极高。这不是语法错误,而是典型的索引失效场景。
正确做法是改用范围查询:
WHERE create_time >= '2024-05-01' AND create_time <p>或者用 <code>YEAR()</code> + <code>MONTH()</code> 组合(仍不如范围高效,但比 <code>DATE_FORMAT</code> 稍好);若必须格式化后比较,应将格式化逻辑移到应用层处理。</p>
- 视图或报表 SQL 中用
DATE_FORMAT输出没问题,但绝不该出现在过滤条件里 - 如果字段是
DATE类型,DATE_FORMAT(col, '%Y%m%d')和col本身在 B-tree 索引中存储方式完全不同,无法对齐
跨数据库兼容性替代方案
PostgreSQL 用 TO_CHAR(col, 'YYYY-MM-DD'),SQL Server 用 FORMAT(col, 'yyyy-MM-dd') 或 CONVERT(varchar, col, 120),SQLite 用 strftime('%Y-%m-%d', col)。这些函数名字、参数顺序、格式符都不统一,硬写 DATE_FORMAT 会让迁移成本陡增。
如果项目需要多数据库支持,建议在 ORM 层(如 SQLAlchemy、MyBatis)或应用代码中做适配,而不是在 SQL 里强依赖 MySQL 特性。
- MySQL 8.0+ 支持
CAST(col AS CHAR)配合DATE类型隐式转换,但结果固定为YYYY-MM-DD格式,不可定制 - 某些 BI 工具(如 Metabase、Superset)自带日期格式化配置项,优先用界面设置,避免污染 SQL
真正麻烦的不是记不住 %k 和 %H 的区别,而是忘了它只属于 MySQL,以及在 WHERE 里随手一写就让慢查询日志爆掉。











