使用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个月来对语句进行编码?
答案 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