SQL:生成过去12个月的汇总结果表,不包括当前月份

时间:2017-09-06 12:26:44

标签: sql-server sql-server-2008 tsql

使用SQL Server 2008 R2,我编写了一些代码来生成聚合结果表,该表计算该月内所有约会的平均等待时间(从推荐到约会日期)。

根据运行查询的任何一天,我希望它生成一个前12个完整个月的结果表,不包括当前月份。例如,如果我今天(2017年9月6日)运行查询,我希望结果表在2017年8月至2016年9月期间为我提供12行,如下所示:

YEAR | MONTH | MONTHNAME | AVG DAYS WAIT
-----+-------+-----------+---------------
2017 |   8   |  August   |     42
2017 |   7   |   July    |     43
2017 |   6   |   June    |     47
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2016 |   9   | September |     42

我使用下面的代码确实给了我一个12个月的清单并排除当前月份:

SELECT 
     year (OP.Appointment_Date) [Year]
    ,month (OP.Appointment_Date) [Month]
    ,DATENAME (month,OP.Appointment_Date) [MonthName]
    ,AVG(DATEDIFF (dd,OP.Received_Date,Appointment_Date)) [Avg Days Wait]

FROM 
    [HDM_Local].[Outpatients].[vw_OP_Appointments] OP WITH (NOLOCK)

WHERE 
    OP.Appointment_Date >= DATEADD(month, -12, GETDATE())
    AND OP.Appointment_Date < DATEADD(month, -1, GETDATE())

GROUP BY 
     year(OP.Appointment_Date)
    ,month(OP.Appointment_Date)
    ,DATENAME(month,OP.Appointment_Date)

ORDER BY 
     year(OP.Appointment_Date)desc
    ,month(OP.Appointment_Date)desc

然而,我发现的问题是最近一个月(八月)的结果不正确。

通过验证我的数据,我知道8月的平均等待时间是42天。上面的查询实际上给了我一个50的数字。

我假设发生了AND OP.Appointment_Date < DATEADD(month, -1, GETDATE())声明今天的日期,从中减去整整一个月的天数,然后再计算8月份约会的平均等待时间仅基于8月1日至6日期间的约会(或类似的约定)。

同样的问题似乎也影响了列表中最早的月份的结果,我再次假设是因为它忽略了2016年9月执行计算时的前5/6天。

请任何人都可以解释如何根据每个月内的完整日期范围&#34; 来有效地&#34;忽略当前月份并返回前12个月来对语句进行编码?

3 个答案:

答案 0 :(得分:0)

您的where子句减去了几个月,但没有截断到每个月的开头。

这将为您提供从12个月前的月份的第一天到上个月末的范围:

where op.Appointment_Date >= dateadd(month, datediff(month, 0, getdate() )-12, 0)
  and op.Appointment_Date <  dateadd(month, datediff(month, 0, getdate() ), 0)

以下是您的日期范围与截断日期范围的比较:

select 
    TruncatedToMonth = 'N'
  , fromdate = dateadd(month, -12, getdate())
  , thrudate = dateadd(month, -1, getdate())
union all 
select 
    TruncatedToMonth = 'Y'
  , fromdate = dateadd(month, datediff(month, 0, getdate() )-12, 0)
  , thrudate = dateadd(month, datediff(month, 0, getdate() ), 0)

rextester演示:http://rextester.com/RGJ79943

返回:

+------------------+---------------------+---------------------+
| TruncatedToMonth |      fromdate       |      thrudate       |
+------------------+---------------------+---------------------+
| N                | 2016-09-06 14:38:07 | 2017-08-06 14:38:07 |
| Y                | 2016-09-01 00:00:00 | 2017-09-01 00:00:00 |
+------------------+---------------------+---------------------+

答案 1 :(得分:0)

WHERE     OP.Appointment_Date&gt; = DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()) - 12,0)     AND OP.Appointment_Date&lt; DATEADD(月,DATEDIFF(月,-1,GETDATE()) - 1,-1)

- 或 -

WHERE     DATEADD之间的OP.Appointment_Date(月,DATEDIFF(月,0,GETDATE()) - 12,0)     和DATEADD(月,DATEDIFF(月,-1,GETDATE()) - 1,-1)

基本上: 选择DATEADD(MONTH,DATEDIFF(月,0,GETDATE()) - 1,0) - 上个月的第一天 选择DATEADD(月,DATEDIFF(月,-1,GETDATE()) - 1,-1) - 上个月的前一天

答案 2 :(得分:0)

我个人会从where子句中删除你的逻辑并将它们放入一个变量中,因为它们不依赖于列(这将减少你的开销,无论是可忽略的数量还是实质的,具体取决于你的数据库)。

在where子句中尝试这些变量,应该从2016年9月初到2017年8月底返回

DECLARE @MinDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) -- Get start of month 13 months before current
DECLARE @MaxDate DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), -1) -- Get end of latest month before current

SELECT @MinDate, @MaxDate

编辑:重新阅读你的帖子。 DATEADD MONTH的工作方式是逐字增加或减去该日期的月数,即如果是2017年9月6日,则需要从2016年9月6日返回12个月。您可以随时使用类似的条款从WHERE子句中取出并将它们放入选择中以查看它们所具有的效果,即:

SELECT DATEADD(month, -12, GETDATE()), DATEADD(month, -1, GETDATE())

返回

(No column name)              (No column name)
2016-09-06 18:45:07.857       2017-08-06 18:45:07.857