在SQL Server中获取上个月的记录


77

我想根据我的数据库表[member]字段“ date_created”获取上个月的记录。

什么是SQL来做到这一点?

为了澄清起见,上个月-2009年1月8日至2009年8月31日

如果今天是2010年3月1日,我需要获取2009年1月12日至2009年12月31日的记录。


2
“上个月”是指“最近30天”,“上个月的所有天”还是“当月的所有天”?
Cellfish

最佳语法还取决于您使用的是带有DATETIME字段的SQL 2005(或更早版本)还是带有DATE字段的SQL 2008。
eidylon

4
DATEDIFF(month, date_created, GETDATE()) = 1呢 那还行吗?
Philipp M

Answers:


115
SELECT * 
FROM Member
WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, date_created) = DATEPART(yyyy, DATEADD(m, -1, getdate()))

您需要检查月份和年份。


2
就我而言, SELECT * FROM Member WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate())) AND DATEPART(yy, date_created) = DATEPART(yy, DATEADD(m, -1, getdate()))效果很好
gofor.net,2012年

9
这种方法将忽略表上的所有索引,并在每次运行表时对其进行扫描(或聚集索引)。表越大,查询将花费的时间越长。
mrdenny 2012年

5
您必须使用yyyy而不是y
inser 2013年

105

所有现有的(有效的)答案都具有以下两个问题之一:

  1. 他们将忽略正在搜索的列上的索引
  2. (可能)会选择不需要的数据,从而无意中破坏您的结果。

1.忽略的索引:

在大多数情况下,当要搜索的列具有调用的函数时(包括隐式的,如for CAST),优化器必须忽略该列上的索引并搜索每条记录。这是一个简单的例子:

我们正在处理时间戳,大多数RDBMS倾向于以某种递增的值(通常为1毫秒longBIGINTEGER毫秒)存储此信息。因此,当前时间看起来/存储如下:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT

您没有在其中看到“年”值('2014'),对吗?实际上,有很多复杂的数学来回翻译。因此,如果您在搜索列中调用任何提取/日期部分函数,​​则服务器必须执行所有数学运算,才能弄清楚是否可以将其包括在结果中。在小型表上,这不是问题,但是随着所选行的百分比减少,这将变得越来越大。然后,在这种情况下,您需要第二次询问MONTH...好了,您知道了。

2.意外数据:

取决于在SQL Server的特定版本,并且列数据类型,使用BETWEEN(或类似的含上限范围:<=可能导致错误的数据被选择。本质上,您可能最终会包含“第二天”午夜以来的数据,或者排除“当前”天记录的某些部分。

该做什么:

因此,我们需要一种对数据安全的方法,并使用索引(如果可行)。正确的方式为:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

鉴于只有一个月,@startOfPreviousMonth可以很容易地用以下方法代替/派生:

DATEADD(month, -1, @startOCurrentfMonth)

如果您需要在服务器中导出当前月份的开始,则可以通过以下方法进行操作:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

快速解释一下。初始值DATEDIFF(...)将获得当前时代开始之间的差异(0001-01-01-AD,CE,等等),本质上返回一个大整数。这是几个月来的开始计数当前的月份。然后,我们将该数字添加到时代的开始,即给定月份的开始。

因此,您的完整脚本可能/应该类似于以下内容:

DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally    misspelled
      AND date_created < @startOfCurrentMonth

因此,所有日期运算仅对一个值执行一次;优化器可以自由使用索引,并且不会包含任何不正确的数据。


8
我真的希望,即使这使我失去声誉,我也可以多次投票。做得好。
诺克斯

2
你是个天才!我很感谢您写的一个简短的反馈,不要误以为是。出色的工作!我也同意@knox
bird2920 '17

这应该是最好的答案。另外感谢您提供的信息“ BETWEEN”在这种情况下不起作用,因为它将占用额外的一天。
cosan

11

添加到目前为止提供的选项根本不会使用您的索引。

这样的事情将可以解决问题,并利用表上的索引(如果存在)。

DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

很抱歉无法投票,但无法正常工作:尝试使用“ 12/31/2013 11:59”作为反例(返回“ 2013-10-30 11:59:00.000”和“ 2013-11-30 11”之间的行: 59:00.000'(在SQL Server上)。
Daniel Cotter

1
getdate()给您当前时间。我认为您应该从12:00 AM(一天开始)开始。@Rokas的答案是正确的。如果要查看,请打印开始时间和结束时间。
madhu_karnati

10
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET @EndDate = DATEADD(mm, 1, @StartDate)

SELECT *
FROM Member
WHERE date_created BETWEEN @StartDate AND @EndDate

升级到mrdenny的解决方案,这样您就可以从YYYY-MM-01上个月获得


3

上个月考虑到该月的最后一天。2016年3月31日,这里的最后一天是1月31日,与过去30天不同。

SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))

1

一种方法是使用DATEPART函数:

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) = 4 
and DATEPART(year, date_created) = 2009

将返回4月的所有日期。对于上个月(即,本月之前的月份),您还可以使用GETDATEDATEADD

select field1, field2, fieldN from TABLE where DATEPART(month, date_created) 
= (DATEPART(month, GETDATE()) - 1) and 
DATEPART(year, date_created) = DATEPART(year, DATEADD(m, -1, GETDATE()))

3
这种方法将忽略表上的任何索引,并在每次运行表时对其进行扫描(或聚集索引)。表越大,查询将花费的时间越长。
mrdenny

1
declare @PrevMonth as nvarchar(256)

SELECT @PrevMonth = DateName( month,DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)) + 
   '-' + substring(DateName( Year, getDate() ) ,3,4)

1

SQL查询仅获取当前月份的记录

SELECT * FROM CUSTOMER
WHERE MONTH(DATE) = MONTH(CURRENT_TIMESTAMP) AND YEAR(DATE) = YEAR(CURRENT_TIMESTAMP);

0
select * from [member] where DatePart("m", date_created) = DatePart("m", DateAdd("m", -1, getdate())) AND DatePart("yyyy", date_created) = DatePart("yyyy", DateAdd("m", -1, getdate()))

2
尽管此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的其他上下文,可以提高其长期价值。
β.εηοιτ.βε

0
DECLARE @StartDate DATETIME, @EndDate DATETIME    
SET @StartDate = DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)    
SET @EndDate = dateadd(dd, -1, DATEADD(mm, 1, @StartDate))

SELECT * FROM Member WHERE date_created BETWEEN @StartDate AND @EndDate 

以及对mrdenny解决方案的另一次升级。
它也给出了上个月的确切日期。


0
WHERE 
    date_created >= DATEADD(MONTH, DATEDIFF(MONTH, 31, CURRENT_TIMESTAMP), 0)
    AND date_created < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)

一点解释?
cheesemacfly 2013年

0

我来自Oracle env,我会在Oracle中这样做:

select * from table
where trunc(somedatefield, 'MONTH') =
trunc(sysdate -INTERVAL '0-1' YEAR TO MONTH, 'MONTH')

想法:我正在运行上个月的计划报告(从第1天到该月的最后一天,没有窗口)。这可能对索引不友好,但是Oracle仍然具有快速的日期处理能力。MS SQL中是否有类似的简便方法?分别比较年份和月份的答案对Oracle员工来说似乎很愚蠢。


0

您可以通过此查询获取上个月的记录

SELECT * FROM dbo.member d 
WHERE  CONVERT(DATE, date_created,101)>=CONVERT(DATE,DATEADD(m, datediff(m, 0, current_timestamp)-1, 0)) 
and CONVERT(DATE, date_created,101) < CONVERT(DATE, DATEADD(m, datediff(m, 0, current_timestamp)-1, 0),101) 

0

我认为接受的解决方案不是非常友好的索引,我改用以下几行

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date <= dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

或者简单地(这是最好的)。

select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date < SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);

一些帮助

-- Get the first of last month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
-- Get the first of current month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
--Get the last of last month except the last 3milli seconds. (3miliseconds being used as SQL express otherwise round it up to the full second (SERIUSLY MS)
SELECT dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));

-1

在Sql Server中最近一个月:

select * from tablename 
where order_date > DateAdd(WEEK, -1, GETDATE()+1) and order_date<=GETDATE()

-1
DECLARE @curDate INT = datepart( Month,GETDATE())
IF (@curDate = 1)
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=12 AND datepart(Year,Created_Date) = (datepart(Year,GETDATE())-1)

    END
ELSE
    BEGIN
        select * from Featured_Deal
        where datepart( Month,Created_Date)=(datepart( Month,GETDATE())-1) AND datepart(Year,Created_Date) = datepart(Year,GETDATE())

    END 

-1
DECLARE @StartDate DATETIME, @EndDate DATETIME
SET @StartDate = dateadd(mm, -1, getdate())
SET @StartDate = dateadd(dd, datepart(dd, getdate())*-1, @StartDate)
SET @EndDate = dateadd(mm, 1, @StartDate)
set @StartDate = DATEADD(dd, 1 , @StartDate)

-1

我解决类似问题的方法是在“选择”部分中添加“月份”

Month DATEADD(day,Created_Date,'1971/12/31') As Month

然后我添加了WHERE语句

Month DATEADD(day,Created_Date,'1971/12/31') = month(getdate())-1

-1

如果您正在寻找上个月,请尝试此操作,

SELECT
FROM  #emp 
WHERE DATEDIFF(MONTH,CREATEDDATE,GETDATE()) = 1

如果您正在寻找上个月,请尝试此操作,

SELECT
FROM #emp
WHERE DATEDIFF(day,CREATEDDATE,GETDATE()) between 1 and 30

1
请阅读前面的答案,以了解为什么这是行不通的,以及/或者在人们否决它之前没有正确的方法。也许您想删除您的回复。
Cetin Basoz

嗨,欢迎来到Stack Overflow。当回答已经有很多答案的问题(17!)时,请确保添加一些其他见解,以了解您所提供的仓促组成的回答为何具有实质性意义,而不仅仅是回溯原始海报已审核的内容。在像您这样的“仅代码”答案中,这一点尤其重要。
CHB

-1

一个对我有用的简单查询是:

从表中选择*,其中DATEADD(month,1,DATEFIELD)> = getdate()


-1

如果您正在寻找上个月的数据:

date(date_created)>=date_sub(date_format(curdate(),"%Y-%m-01"),interval 1 month) and 
date(date_created)<=date_sub(date_format(curdate(),'%Y-%m-01'),interval 1 day)

当年份更改时,这也将起作用。它也可以在MySQL上运行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.