datediff函数计算天数差异需按数据库适配:mysql用datediff(end,start),sql server用datediff(unit,start,end),postgresql原生不支持而用日期相减;参数顺序、单位指定和null处理各不同,且函数包裹列会导致索引失效。

SQL DATEDIFF 函数计算天数差异的基本用法
DATEDIFF 不是标准 SQL 函数,不同数据库实现差异大,不能直接跨库照搬。MySQL 用 DATEDIFF(date1, date2),SQL Server 和 PostgreSQL(需 pg_catalog 扩展)则用 DATEDIFF('day', start_date, end_date) 或类似变体。核心区别在于参数顺序和单位指定方式。
常见错误:在 MySQL 中写成 DATEDIFF('day', '2023-01-01', '2023-01-10') 会报错,因为 MySQL 的 DATEDIFF 只接受两个日期参数,且返回的是 date1 - date2 的天数差(正负取决于顺序)。
- MySQL:
DATEDIFF('2023-01-10', '2023-01-01')→ 返回9 - SQL Server:
DATEDIFF(day, '2023-01-01', '2023-01-10')→ 返回9 - PostgreSQL:原生无
DATEDIFF,用'2023-01-10'::date - '2023-01-01'::date更直接
为什么结果可能是负数?参数顺序怎么记
几乎所有支持 DATEDIFF 的数据库都按“结束时间减开始时间”逻辑,但参数顺序不统一。SQL Server 是 DATEDIFF(unit, start, end);MySQL 是 DATEDIFF(end, start) —— 表面看都是“后减前”,但函数名里的“DIFF”容易让人误以为是“第一个减第二个”,实际要看文档。
最容易踩的坑:把日期字符串格式写错,比如用 '01/10/2023' 在某些区域设置下被解析为 2023-10-01,导致差值翻倍或出负数。
- 始终用 ISO 格式
'YYYY-MM-DD',避免歧义 - 对字段计算时,确认字段类型是
DATE或DATETIME,不是VARCHAR;否则隐式转换可能失败或偏差 - MySQL 中若传入
NULL,结果直接为NULL,不会报错,容易漏掉数据异常
替代方案:不用 DATEDIFF 也能算天数差
标准 SQL 更推荐用日期相减,兼容性更好。PostgreSQL、Snowflake、BigQuery 都支持 date_col - other_date_col 直接得整数天数;MySQL 也支持 TO_DAYS(date1) - TO_DAYS(date2)(但注意 TO_DAYS 对 NULL 返回 NULL)。
如果目标库不确定,或者要写跨平台 SQL,优先考虑显式转换 + 减法:
- PostgreSQL / BigQuery:
end_date::date - start_date::date - MySQL:
DATEDIFF(end_date, start_date)最简,但仅限该库 - SQLite:
julianday(end_date) - julianday(start_date)
性能与索引影响:能用 WHERE 就别用 DATEDIFF 包裹列
在 WHERE 条件里写 DATEDIFF(CURDATE(), created_at) > 30,会让 created_at 列无法走索引(函数包裹列 = 索引失效)。正确做法是把函数移到右边:
- ❌
WHERE DATEDIFF(CURDATE(), created_at) > 30 - ✅
WHERE created_at (MySQL) - ✅
WHERE created_at (PostgreSQL)
这个细节在数据量大时直接影响查询速度,很多人调优时才意识到。
真正麻烦的不是语法本身,而是每个数据库对“日期”的定义不同:有的忽略时分秒,有的严格比较时间戳,有的自动截断。算天数前,先确认你比的是“日历日差”还是“精确小时差向下取整”。











