😩 痛点:那个尴尬的 1 月 1 日

做自动报表统计时,大家都有过这个痛点:
平时查的是 当年 的数据,但唯独在 每年1月1日 这一天,用户希望能自动生成刚结束的 去年全年 报表。

如果你只是简单地以 current_date(当前日期)为基准截取年份,元旦那天跑出来的报表就是空的——因为新的一年才刚开始,哪里来的数据?

💡 核心思路:减一天大法

不需要写复杂的 CASE WHEN,利用日期的连续性,做日期计算前,先把当前日期减去 1 天 (current_date - 1):

  • 平时(如 2026-01-02): 减一天是 2026-01-01 -> 依然算 今年
  • 元旦(如 2026-01-01): 减一天是 2025-12-31 -> 瞬间回到 去年

以下是针对不同字段类型的最佳 SQL 写法:


✅ 场景一:字段是纯日期 (Date)

假设 reportdata 字段类型是 Date(例如存储的是 2025-12-31,不带时分秒)。

推荐写法:使用 BETWEEN 或 >= <=

select * from table 
where 
    -- 1. 起始日期:(当前日期减1天) 所在年份的第一天
    reportdata >= (date_trunc('year', current_date - 1))::date
    AND 
    -- 2. 结束日期:(当前日期减1天) 所在年份的最后一天
    reportdata <= (date_trunc('year', current_date - 1) + interval '1 year - 1 day')::date;

📝 技术要点:

  • 为什么不用 to_char
    直接将计算结果转为 ::date 类型与字段进行比较,可以利用数据库索引,查询效率远高于字符串比较。
  • 为什么加 ::date
    date_trunc 函数默认返回的是 Timestamp(带时分秒,如 2025-01-01 00:00:00)。强转为 Date 类型,保证逻辑严谨,避免类型隐式转换带来的坑。

✅ 场景二:字段带时间 (Timestamp)

假设 reportdata 字段类型是 Timestamp(例如 2025-12-31 15:30:00)。

❌ 常见的错误写法:
使用 <= 去匹配 2025-12-31,这通常会被解析为 2025-12-31 00:00:00,导致当天的白天数据全部丢失。

🚀 完美写法:使用“左闭右开”区间 (< 明年第一天)

select * from table 
where 
    -- 大于等于 年初
    reportdata >= date_trunc('year', current_date - 1)
    AND 
    -- 小于 明年年初 (关键!)
    reportdata <  date_trunc('year', current_date - 1) + interval '1 year'; 

📝 技术要点:

  • 左闭右开原则:
    >= 2025-01-01< 2026-01-01
    这种写法能完美覆盖 2025-12-31 23:59:59.999 这种极限时间,且不需要考虑闰年或每个月到底有多少天,逻辑最健壮。

🚀 总结

  1. 逻辑核心:利用 current_date - 1 处理跨年边界。
  2. 纯日期字段:用 ::date 强转,使用 <= 涵盖最后一天。
  3. 带时间字段:不要用 <=,请用 < 明年1月1日,防止漏掉最后一天的时分秒数据。
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐