获取SQL Server上个月的记录

Bil*_*lly 68 sql t-sql sql-server

我想根据我的db table [member]字段"date_created"获取上个月的记录.

sql是做什么的?

澄清,上个月 - 2009年1月8日至2009年8月31日

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

Dav*_*ker 100

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()))
Run Code Online (Sandbox Code Playgroud)

你需要检查月份和年份.

  • 此方法将忽略表上的所有索引,并在每次运行时执行表(或聚簇索引)扫描.表越大,查询所需的时间越长. (8认同)
  • 你必须使用yyyy而不是y (4认同)
  • 在我的情况下`SELECT*FROM Member WHERE DATEPART(m,date_created)= DATEPART(m,DATEADD(m,-1,getdate()))和DATEPART(yy,date_created)= DATEPART(yy,DATEADD(m,-1) ,getdate()))`工作完美 (2认同)

Clo*_*use 81

所有现有(工作)答案都有两个问题之一:

  1. 他们将忽略被搜索列的索引
  2. 意志(可能)选择不打算的数据,静默地破坏您的结果.

1.忽略指数:

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

我们正在处理的时间戳,大多数的RDBMS倾向于此信息存储为某种类型的增加值,通常是一个longBIGINTEGER的毫/纳秒数.因此,当前时间看起来像这样存储:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT
Run Code Online (Sandbox Code Playgroud)

你没有'2014'在那里看到'年'值(),对吗?事实上,来回翻译需要相当复杂的数学.因此,如果您在搜索列上调用任何提取/日期部分函数,​​则服务器必须执行所有数学计算,以确定是否可以将其包含在结果中.在小桌子上这不是问题,但随着所选行的百分比减少,这变得越来越大.那么在这种情况下,你第二次做这个问题MONTH......好吧,你得到了照片.

2.意外数据:

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

该做什么:

所以我们需要一种对我们的数据安全的方法,并且将使用索引(如果可行).那么正确的方式是:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth
Run Code Online (Sandbox Code Playgroud)

鉴于只有一个月,@startOfPreviousMonth可以很容易地替换/派生:

DATEADD(month, -1, @startOCurrentfMonth)
Run Code Online (Sandbox Code Playgroud)

如果需要在服务器中派生当前月初,可以通过以下方式完成:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
Run Code Online (Sandbox Code Playgroud)

这里有一个简短的解释.初始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
Run Code Online (Sandbox Code Playgroud)

因此,所有日期操作仅在一个值上执行一次; 优化器可以自由使用索引,并且不会包含不正确的数据.

  • 我真的希望即使它让我失去声誉,我也可以不止一次地投票.做得好. (7认同)
  • 你是个天才!我很欣赏一个写得很好的回复,不贬低,只是通知。伟大的工作!我也同意@knox (2认同)

mrd*_*nny 12

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

像这样的东西会起作用,并利用表上的索引(如果存在).

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
Run Code Online (Sandbox Code Playgroud)


小智 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
Run Code Online (Sandbox Code Playgroud)

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


M20*_*012 5

上个月视为该月的最后一天。2016 年 1 月 31 日,该月的最后一天是 1 月 31 日,这与过去 30 天不同。

SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))
Run Code Online (Sandbox Code Playgroud)