电脑港
白蓝主题五 · 清爽阅读
首页  > 软件应用

SQL查询上个月数据,一条语句搞定(MySQL/PostgreSQL/SQL Server实测)

ref="/tag/426/" style="color:#B2A89E;font-weight:bold;">数据分析、财务对账或者后台报表时,经常要查“上个月的数据”,比如:上个月的订单量、用户注册数、销售总额。写错时间范围,轻则数据不准,重则老板找你喝茶。

别硬写具体日期,用函数才靠谱

很多人图省事,手动写成 WHERE order_date BETWEEN '2024-02-01' AND '2024-02-29' —— 这样下次跑就失效了。正确做法是让数据库自己算“上个月第一天”和“上个月最后一天”。

MySQL 写法(最常用)

直接用 LAST_DAYDATE_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);

小提醒,避坑三件事

① 字段类型要是 DATEDATETIME,别用字符串存日期,否则索引失效,查得慢还容易出错;
② 如果字段含时间(比如 '2024-02-15 14:30:22'),用 < 本月1号比用 <= 上月最后一天更安全,避免漏掉最后一秒;
③ 测试时别只看“结果对不对”,顺手加个 SELECT COUNT(*) 对比下上个月的总条数,心里更有底。

在电脑港后台改过三次报表 SQL 的老王说:“以前每月初都要手动改日期,有次忘改,导出的‘上月销量’其实是前年数据……现在贴好模板,一键复制,稳。”