如何修改SQL WHERE子句以跨年度获取上月数据?
解决跨年时获取上月数据的SQL查询问题
这个坑我踩过好多次!跨年的时候这种拆分月份和年份单独判断的写法很容易失效,咱们来搞定它。
原查询的问题所在
你原来的语句把年份固定成了当前年份,但跨年时(比如现在是2019年1月),上月其实是2018年12月,这时候年份条件DATEPART(yyyy, a.meetDate) = DATEPART(yyyy, getdate())就不匹配了,自然查不到数据。
推荐的修改方案
我给你三种可行的写法,优先推荐第一种,因为它逻辑清晰还能利用索引:
方案1:用日期区间匹配(最推荐)
直接计算出上月的第一天和最后一天,然后判断meetDate是否在这个区间内:
-- 先定义上月的起始和结束日期 DECLARE @LastMonthStart DATE = DATEADD(month, DATEDIFF(month, 0, GETDATE()) - 1, 0) DECLARE @LastMonthEnd DATE = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)) SELECT * FROM somedatabase a WHERE a.meetDate BETWEEN @LastMonthStart AND @LastMonthEnd
- 解释:
DATEADD(month, DATEDIFF(month, 0, GETDATE()) - 1, 0)会精准获取上月的第一天(比如2019年1月时得到2018-12-01); DATEADD(day, -1, ...)则是取当月第一天的前一天,也就是上月最后一天;- 这种写法不管跨不跨年都能准确匹配,而且因为是直接对
meetDate列做范围判断,能用到该列上的索引,性能更好。
方案2:用月份差判断
如果不想用变量,也可以直接用DATEDIFF判断月份差:
SELECT * FROM somedatabase a WHERE DATEDIFF(month, a.meetDate, GETDATE()) = 1
- 解释:
DATEDIFF(month, 日期1, 日期2)会返回两个日期之间的月份数差,这里等于1就表示meetDate是上个月的日期,不管年份是否跨年都成立。
方案3:调整原语句的年份判断
如果你想保留原来的结构,只需要把年份判断改成取上月的年份,而不是当前年份:
SELECT * FROM somedatabase a WHERE DATEPART(m, a.meetDate) = DATEPART(m, DATEADD(m, -1, GETDATE())) AND DATEPART(yyyy, a.meetDate) = DATEPART(yyyy, DATEADD(m, -1, GETDATE()))
- 解释:原来的年份取的是
GETDATE()的年份,现在改成取DATEADD(m, -1, GETDATE())的年份,跨年时自动变成去年,就能匹配到12月的数据了。不过这种写法因为对meetDate做了函数运算,可能无法利用索引,性能不如方案1。
总结
优先选方案1,它不仅解决了跨年问题,还兼顾了性能和可读性,几乎不会有边界情况。
内容的提问来源于stack exchange,提问作者SJG
相关产品推荐
相关产品推荐

