PostgreSQL如何正确对比当月同日与上月同日的数据?
解决PostgreSQL中获取上月对应日期的坑
嘿,这个问题我之前做报表的时候也踩过!用current_date - interval '1 month'确实会在月末的特殊日期翻车——比如3月31日减一个月,PostgreSQL会试图生成2月31日,这显然不存在,直接就报错了。针对你的需求(对比当月和上月对应日期的value),我给你几个实用的解决方案:
方法1:容错式获取(自动取上月最后一天)
如果业务上允许当月日期在上月不存在时,自动取上月的最后一天(比如3月31日对应2月28/29日),可以用这个写法:
SELECT t.date AS current_date, t.value AS current_value, -- 计算上月对应日期,不存在则取上月最后一天 ( date_trunc('month', t.date) - interval '1 month' + (LEAST(EXTRACT(DAY FROM t.date), EXTRACT(DAY FROM (date_trunc('month', t.date) - interval '1 day'))) - 1) * interval '1 day' )::date AS last_month_date, t_last.value AS last_month_value FROM your_table t LEFT JOIN your_table t_last ON t_last.date = ( date_trunc('month', t.date) - interval '1 month' + (LEAST(EXTRACT(DAY FROM t.date), EXTRACT(DAY FROM (date_trunc('month', t.date) - interval '1 day'))) - 1) * interval '1 day' )::date -- 如果你只查当前日期的数据,加上这个条件 WHERE t.date = CURRENT_DATE;
原理是先拿到上月的第一天,再根据当前日期的日数和上月最后一天的日数取较小值,避免生成不存在的日期。
方法2:严格匹配(不存在则报错)
如果业务要求必须严格对应日期,不存在就抛出提示,可以用make_date函数,它会在日期非法时直接报错:
SELECT t.date AS current_date, t.value AS current_value, MAKE_DATE( EXTRACT(YEAR FROM t.date)::INT, EXTRACT(MONTH FROM t.date)::INT - 1, EXTRACT(DAY FROM t.date)::INT ) AS last_month_date, t_last.value AS last_month_value FROM your_table t LEFT JOIN your_table t_last ON t_last.date = MAKE_DATE( EXTRACT(YEAR FROM t.date)::INT, EXTRACT(MONTH FROM t.date)::INT - 1, EXTRACT(DAY FROM t.date)::INT ) WHERE t.date = CURRENT_DATE;
比如当前是3月31日,这个查询会直接返回date field value out of range的错误,适合需要严格校验的场景。
方法3:简化版(针对当前日期)
如果你只需要查询当前日期对应的上月数据,也可以用更简洁的写法:
-- 容错版 SELECT * FROM your_table WHERE date = ( CASE WHEN EXTRACT(DAY FROM CURRENT_DATE) <= EXTRACT(DAY FROM (date_trunc('month', CURRENT_DATE) - interval '1 day')) THEN CURRENT_DATE - interval '1 month' ELSE (date_trunc('month', CURRENT_DATE) - interval '1 day')::date END ); -- 严格版 SELECT * FROM your_table WHERE date = MAKE_DATE( EXTRACT(YEAR FROM CURRENT_DATE)::INT, EXTRACT(MONTH FROM CURRENT_DATE)::INT - 1, EXTRACT(DAY FROM CURRENT_DATE)::INT );
根据你的业务需求选对应的方法就好啦!
内容的提问来源于stack exchange,提问作者c3win90
相关产品推荐
相关产品推荐

