如何在SQL中筛选到上个月(避免1月份出现问题)

如何在SQL中筛选到上个月(避免1月份出现问题),sql,sql-server,datepart,Sql,Sql Server,Datepart,在SQL中,我希望提取只适用于上个月的数据。这是我使用DATEPART函数完成的,如果我检查DATEPART函数中的'M'从当前日期算起为-1,它就可以正常工作。但是当我到了一月份的时候,我会遇到一些问题,因为当然没有一个月份是1小于1的 有没有一种方法可以避免SQL中出现我不知道或想不到的问题 我当前的语法如下 (DATEPART(M,p.renewal_date_key) = DATEPART(M,dateadd(M,-1,getdate())) 然后我还有一个DATEPART子句,它对该

在SQL中,我希望提取只适用于上个月的数据。这是我使用DATEPART函数完成的,如果我检查DATEPART函数中的'M'从当前日期算起为-1,它就可以正常工作。但是当我到了一月份的时候,我会遇到一些问题,因为当然没有一个月份是1小于1的

有没有一种方法可以避免SQL中出现我不知道或想不到的问题

我当前的语法如下

(DATEPART(M,p.renewal_date_key) = DATEPART(M,dateadd(M,-1,getdate()))
然后我还有一个DATEPART子句,它对该年执行相同的操作,以确保该年的值与当前年份相同

任何关于避免1月份问题的替代方法的想法都会大有裨益


顺便说一句,这在Microsoft中也有使用(SQL Server和一些历史性的Excel Power查询中也有使用)

从准确性和性能角度来看,最好的方法是计算上个月的开始日期和结束日期,然后使用这些日期与您的日期进行比较。您希望避免在列上使用函数,因为这排除了使用索引的可能性(即查询不再是可搜索的)

下面是一个例子,我使用它作为函数来避免重新编码

由于执行比较的方式,这也会处理
date
datetime
数据类型

declare @StartDate date = dateadd(day, 1, eomonth(sysdatetime(),-2)), @EndDate date = eomonth(sysdatetime(),-1);

select *
from MyTable
where MyDate >= @StartDate 
and MyDate < dateadd(day, 1, @EndDate);
declare@StartDate date=dateadd(day,1,eomonth(sysdatetime(),-2)),@EndDate date=eomonth(sysdatetime(),-1);
挑选*
从MyTable
其中MyDate>=@StartDate
和MyDate
或者您可以将其内联:

select *
from MyTable
where MyDate >= dateadd(day, 1, eomonth(sysdatetime(),-2)) 
and MyDate < dateadd(day, 1, eomonth(sysdatetime(),-1));
选择*
从MyTable
其中MyDate>=dateadd(天,1,月(sysdatetime(),-2))
和MyDate
从准确性和性能角度来看,最好的方法是计算上个月的开始日期和结束日期,然后使用这些日期与您的日期进行比较。您希望避免在列上使用函数,因为这排除了使用索引的可能性(即查询不再是可搜索的)

下面是一个例子,我使用它作为函数来避免重新编码

由于执行比较的方式,这也会处理
date
datetime
数据类型

declare @StartDate date = dateadd(day, 1, eomonth(sysdatetime(),-2)), @EndDate date = eomonth(sysdatetime(),-1);

select *
from MyTable
where MyDate >= @StartDate 
and MyDate < dateadd(day, 1, @EndDate);
declare@StartDate date=dateadd(day,1,eomonth(sysdatetime(),-2)),@EndDate date=eomonth(sysdatetime(),-1);
挑选*
从MyTable
其中MyDate>=@StartDate
和MyDate
或者您可以将其内联:

select *
from MyTable
where MyDate >= dateadd(day, 1, eomonth(sysdatetime(),-2)) 
and MyDate < dateadd(day, 1, eomonth(sysdatetime(),-1));
选择*
从MyTable
其中MyDate>=dateadd(天,1,月(sysdatetime(),-2))
和MyDate
使用该功能。

使用
EOMONTH(续订日期键)
可以获得
续订日期键
月份的最后一天的日期,使用
EOMONTH(GETDATE(),-1)
可以获得上个月的最后一天。
像这样写
WHERE
子句:

WHERE EOMONTH(renewal_date_key) = EOMONTH(GETDATE(), -1)
或者如果
续订日期\u键
的数据类型为
日期

WHERE renewal_date_key > EOMONTH(GETDATE(), -2)
  AND renewal_date_key <= EOMONTH(GETDATE(), -1)
其中续订日期\u key>EOMONTH(GETDATE(),-2)
和更新日期键使用该功能。

使用
EOMONTH(续订日期键)
可以获得
续订日期键
月份的最后一天的日期,使用
EOMONTH(GETDATE(),-1)
可以获得上个月的最后一天。
像这样写
WHERE
子句:

WHERE EOMONTH(renewal_date_key) = EOMONTH(GETDATE(), -1)
或者如果
续订日期\u键
的数据类型为
日期

WHERE renewal_date_key > EOMONTH(GETDATE(), -2)
  AND renewal_date_key <= EOMONTH(GETDATE(), -1)
其中续订日期\u key>EOMONTH(GETDATE(),-2)

最简单的方法是:

 where datediff(month, p.renewal_date_key, getdate()) = 1
然而,这不是索引友好的。对于优化器友好的版本,可以使用
datefromparts()
构造日期:

其中p.renewal\u date\u key=dateadd(月-1,datefromparts(年(getdate()),月(getdate()),1))

请注意,即使“日期”列包含时间组件,这些版本也可以工作。

最简单的方法是:

 where datediff(month, p.renewal_date_key, getdate()) = 1
然而,这不是索引友好的。对于优化器友好的版本,可以使用
datefromparts()
构造日期:

其中p.renewal\u date\u key=dateadd(月-1,datefromparts(年(getdate()),月(getdate()),1))

请注意,即使“日期”列包含时间组件,这些版本也可以工作。

这是否回答了您的问题?在datepart函数中使用“M”而不是“month”可以节省多少精力?后者更容易阅读和理解?特别是如果您在代码中添加了一些空格,而不是将其塞进一块,这是否回答了您的问题?在datepart函数中使用“M”而不是“month”可以节省多少精力?后者更容易阅读和理解?特别是如果您在代码中添加了一些空格而不是将其塞满?但不是sargable。@DaleK第二个解决方案是sargable。但不是sargable。@DaleK第二个解决方案是sargable。那条
convert
行看起来很糟糕,为什么不使用
DATEFROMPARTS
EOMONTH
?当OP只关心日期时,为什么使用datetime数据类型?sysdatetime返回一个datetime2。@SMor,因为我喜欢可能的通用解决方案,这可以用于任何date/datetime/datetime2情况。@Charlieface旧代码,如果没有损坏,请不要修复:)但我会的,因为您指出,
convert
line看起来很糟糕,为什么不使用
DATEFROMPARTS
EOMONTH
?当OP只关心日期时,为什么使用datetime数据类型?sysdatetime返回一个datetime2。@SMor,因为我更喜欢可能的通用解决方案,这可以用于任何date/datetime/datetime2情况。@Charlieface旧代码,如果没有损坏,请不要修复:)但我