做ref="/tag/426/" style="color:#B2A89E;font-weight:bold;">数据分析、财务对账或者后台报表时,经常要查“上个月的数据”,比如:上个月的订单量、用户注册数、销售总额。写错时间范围,轻则数据不准,重则老板找你喝茶。
别硬写具体日期,用函数才靠谱
很多人图省事,手动写成 WHERE order_date BETWEEN '2024-02-01' AND '2024-02-29' —— 这样下次跑就失效了。正确做法是让数据库自己算“上个月第一天”和“上个月最后一天”。
MySQL 写法(最常用)
直接用 LAST_DAY 和 DATE_SUB:
SELECT * FROM orders
WHERE order_date >= DATE_SUB(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY) + INTERVAL 1 DAY
AND order_date <= LAST_DAY(DATE_SUB(NOW(), INTERVAL 1 MONTH));更清爽的写法(推荐):
SELECT * FROM orders
WHERE order_date >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH), '%Y-%m-01')
AND order_date < DATE_FORMAT(NOW(), '%Y-%m-01');原理:取“本月1号”往前推,就是上个月1号;而“本月1号”本身,就是上个月的截止边界(开区间)。
PostgreSQL 写法
SELECT * FROM orders
WHERE order_date >= (CURRENT_DATE - INTERVAL '1 month')::date - EXTRACT(DAY FROM CURRENT_DATE - INTERVAL '1 month')::int + 1
AND order_date < CURRENT_DATE - EXTRACT(DAY FROM CURRENT_DATE)::int;其实更简单——直接用 DATE_TRUNC:
SELECT * FROM orders
WHERE order_date >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '1 month')
AND order_date < DATE_TRUNC('month', CURRENT_DATE);SQL Server 写法
SELECT * FROM orders
WHERE order_date >= DATEFROMPARTS(YEAR(DATEADD(MONTH, -1, GETDATE())), MONTH(DATEADD(MONTH, -1, GETDATE())), 1)
AND order_date < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1);或者更直观的写法(SQL Server 2012+):
SELECT * FROM orders
WHERE order_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 1, 0)
AND order_date < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0);小提醒,避坑三件事
① 字段类型要是 DATE 或 DATETIME,别用字符串存日期,否则索引失效,查得慢还容易出错;
② 如果字段含时间(比如 '2024-02-15 14:30:22'),用 < 本月1号比用 <= 上月最后一天更安全,避免漏掉最后一秒;
③ 测试时别只看“结果对不对”,顺手加个 SELECT COUNT(*) 对比下上个月的总条数,心里更有底。
在电脑港后台改过三次报表 SQL 的老王说:“以前每月初都要手动改日期,有次忘改,导出的‘上月销量’其实是前年数据……现在贴好模板,一键复制,稳。”