加减天数语法不统一:MySQL/PostgreSQL用INTERVAL,SQL Server用DATEADD,SQLite用date()函数;跨库最稳妥是应用层计算或视图封装。

MySQL、PostgreSQL、SQL Server 里加减天数的写法差异
加减天数是兼容性最好的操作,但语法仍不统一。核心区别在于:MySQL 和 PostgreSQL 支持 INTERVAL 表达式,SQL Server 则依赖函数。
- MySQL:
DATE_ADD('2024-01-01', INTERVAL 5 DAY)或简写'2024-01-01' + INTERVAL 5 DAY - PostgreSQL:
'2024-01-01'::DATE + INTERVAL '5 days'(注意单位是复数且带引号) - SQL Server:
DATEADD(day, 5, '2024-01-01')(第一个参数是单数,第二个是数值,第三个是日期) - SQLite:
date('2024-01-01', '+5 days')(字符串拼接式,单位必须小写、带空格和 s)
跨库时若只加减天数,最稳妥的是封装成视图或应用层计算——数据库层硬写兼容 SQL 几乎不可行,因为 INTERVAL 在 SQL Server 中非法,DATEADD 在 MySQL 中不存在。
加减月份必须小心边界日(如 1月31日 + 1月)
月份长度不固定,各库对“溢出日”的处理逻辑不同:MySQL 和 PostgreSQL 默认截断到当月最后一天,SQL Server 默认报错(取决于 DATEADD 行为与 SET 选项),SQLite 不支持直接加月。
- MySQL:
DATE_ADD('2024-01-31', INTERVAL 1 MONTH)→'2024-02-29'(自动取 2 月最后一天) - PostgreSQL:
'2024-01-31'::DATE + INTERVAL '1 month'→ 同样得2024-02-29 - SQL Server:
DATEADD(month, 1, '2024-01-31')→2024-02-29(SQL Server 2012+ 默认也截断,不再报错) - 关键是:不要假设结果一定是“下个月同日”,尤其涉及 1月31日、3月31日等场景;测试时务必覆盖闰年与大小月组合
如果业务要求严格按“日历月”偏移(比如订阅续期),建议在应用层用 datetime 类库做计算,再传入标准化日期,避免数据库隐式修正带来的歧义。
YEAR 的加减在 Oracle 和旧版 SQL Server 中容易出错
Oracle 使用 ADD_MONTHS(date, n*12) 模拟年加减,不是直接加 YEAR;SQL Server 2005 及更早版本的 DATEADD(year, ...) 对 2月29日输入可能返回无效日期(如 DATEADD(year, 1, '2024-02-29') 在某些兼容模式下报错)。
- MySQL/PostgreSQL/SQL Server 2012+:
DATEADD(year, 2, '2023-06-15')或DATE_ADD('2023-06-15', INTERVAL 2 YEAR)都安全 - Oracle:
ADD_MONTHS(date '2023-06-15', 24)是唯一可靠方式;date '2023-06-15' + INTERVAL '2' YEAR语法不支持 - 所有数据库中,
2024-02-29 + 1 YEAR都不会等于2025-02-29(该日不存在),实际结果是2025-02-28或报错——这点比月份更易被忽略
跨库项目若需“加 N 年”,优先走 ADD_MONTHS(..., N * 12) 路线(Oracle 兼容),或彻底移出 SQL,在代码里用 year+1 再 normalize 日期。
没有真正的跨数据库日期加减标准写法
ANSI SQL 标准定义了 INTERVAL 类型,但具体运算符和函数支持程度极不一致。比如 DATE '2024-01-01' + INTERVAL '1' YEAR 在 PostgreSQL 和 MySQL 8.0+ 可用,在 SQL Server 和 SQLite 中直接语法错误。
- 想“写一次,跑多库”?现实是:要么接受最低共性(仅加减天数 + 应用层兜底),要么用 ORM 或查询构建器(如 jOOQ、SQLAlchemy Core)做方言适配
- 临时方案可以建兼容函数视图,例如在各库分别创建
add_days(d DATE, n INT),但维护成本高,且无法覆盖月份/年份逻辑 - 最容易被忽略的点:时区。所有上述操作默认按会话时区或无时区
DATE处理;一旦字段是TIMESTAMP WITH TIME ZONE,PostgreSQL 和 Oracle 的行为又会分叉
真正在意可移植性,就别把复杂日期计算留在 SQL 里——它从来就不是 SQL 的强项。










