为何PostgreSQL中1年间隔与365天间隔不相等?
PostgreSQL跨类型间隔比较的结果差异解析
先看你提供的查询语句:
SELECT CAST('2019-01-01T12:00:00' AS TIMESTAMP) - CAST('2018-01-01T13:00:00' AS TIMESTAMP) <= INTERVAL '365 DAYS', CAST('2019-01-01T12:00:00' AS TIMESTAMP) - CAST('2018-01-01T13:00:00' AS TIMESTAMP) <= INTERVAL '1 YEAR';
第一个表达式返回TRUE,第二个返回FALSE,核心原因在于PostgreSQL对不同类型间隔的处理逻辑,以及它与SQL标准的差异:
1. 间隔类型的本质区别
SQL标准(IEC/ISO 9075-2:2016)将间隔分为两类:
- year-month型间隔:仅包含年、月单位(如
INTERVAL '1 YEAR'),这类间隔的长度不固定,依赖具体的起始日期(不同年份的天数可能不同,不同月份的天数也不同)。 - day-time型间隔:仅包含天、时、分、秒等单位(如两个timestamp相减的结果,
INTERVAL '365 DAYS'),这类间隔的长度是固定的。
标准明确规定,不同类别的间隔不允许直接比较,应该触发类型不兼容错误。
2. PostgreSQL的非标准处理逻辑
PostgreSQL并未严格遵循上述标准,而是对不同类别的间隔执行了隐式转换来完成比较:
- 当比较day-time间隔和year-month间隔时,PostgreSQL会将year-month间隔转换为day-time间隔,转换时采用平均年长度365.25天(即365天6小时),而非你预期的非闰年精确365天。
回到你的查询:
- 两个timestamp相减得到的是
364天23小时的day-time间隔,这个值显然小于365天,因此第一个表达式返回TRUE。 - 而
INTERVAL '1 YEAR'被转换为365天6小时,364天23小时小于这个值,但你得到的结果是FALSE,这可能是PostgreSQL内部转换逻辑的细节差异,但核心问题仍然是跨类型间隔比较的非标准处理导致的预期偏差。
3. 结论与建议
你提到的这个行为更偏向于PostgreSQL的实现问题而非特性:
- 按照SQL标准,这类跨类型间隔比较应该直接报错,而非返回不符合预期的结果。
- 如果你需要精确的年间隔比较,建议基于具体的日期计算(比如将起始日期加上1年,再与结束日期比较),而非直接比较间隔值:
这个查询会返回SELECT CAST('2019-01-01T12:00:00' AS TIMESTAMP) <= CAST('2018-01-01T13:00:00' AS TIMESTAMP) + INTERVAL '1 YEAR';TRUE,因为2018-01-01 13:00:00 +1 YEAR是2019-01-01 13:00:00,2019-01-01 12:00:00确实小于这个时间。
内容的提问来源于stack exchange,提问作者SQLRaptor
相关产品推荐
相关产品推荐

