我有一个表格,其中包含与Date一起访问的报告的信息。我需要根据日期范围对报告进行分组并计算它们。
我正在使用T-SQL
表
EventId ReportId Date
60 4 11/24/2015
59 11 11/23/2015
58 6 11/22/2015
57 11 11/22/2015
56 9 11/21/2015
55 3 11/20/2015
54 5 11/20/2015
53 6 11/19/2015
52 5 11/19/2015
51 4 11/18/2015
50 3 11/17/2015
49 9 11/16/2015
如果天数差异为3,那么我需要格式为
的结果StartDate EndDate ReportsAccessed
11/22/2015 11/24/2015 4
11/19/2015 11/21/2015 5
11/16/2015 11/18/2015 3
但天数之间的差异可能会发生变化。
答案 0 :(得分:4)
假设您拥有所有日期的值,则可以计算每个日期与最大(或最小)日期之间的天数差异。然后将其除以3并将其用于聚合:
select min(date), max(date), count(*) as ReportsAccessed
from (select t.*, max(date) over () as maxd
from table t
) t
group by (datediff(day, date, maxd) / 3)
order by min(date);
“3”是我认为你所指的“日间差异”。
答案 1 :(得分:1)
这2个区块只是为了更清楚地说明您需要更改的参数
DECLARE @t as TABLE(
id int identity(1,1),
reportId int,
dateAccess date)
DECLARE @NumberOfDays int=3;
这是实际的选择
Select StartDate, EndDate, COUNT(reportId) from
(
select *,
DATEADD(day, DATEDIFF(DAY, dateAccess, maxdate.maxdate)%@NumberOfDays, dateAccess) as EndDate,
DATEADD(day, DATEDIFF(DAY, dateAccess, maxdate.maxdate)%@NumberOfDays-@NumberOfDays+1, dateAccess) as StartDate
from @t, (select MAX(dateAccess) maxdate from @t t2) maxdate
) results
GROUP BY StartDate, EndDate
ORDER BY StartDate desc
有些地方我不确定它是否已经过优化,例如使用select max(date)交叉连接而不是使用子查询,但是会返回OP的确切结果。
基本上,我只是根据条目与MAX(date)
的距离将条目分组,然后使用COUNT
。在那个注释中,使用COUNT(distinct ...)
可能更有用,否则如果有人查看文档#9 3次,它会告诉你3个文档被检查,但只有1个真正被查看过。
使用MAX(date)
超过MIN(date)
的好处是,您的第一个群组将始终拥有最长的天数。如果您想将最后几个时段与平均值进行比较,这将非常有用。缺点是您没有稳定的数据。对于每个新条目(假设它是新的一天),您的查询将自行循环以生成一组新结果。如果你想绘制数据图表,你可以更好地与MIN(日期)进行比较,这样当你添加新数据时,前几天不会改变。
根据用途,推断上一期间完成的访问次数甚至可能有用(在这种情况下,MIN(date)
也是优选的。)
以下是戈登答案的改编,可能很多更优化(至少更美观):
SELECT DateADD(day, -datediff(day, dateAccess, maxdate)/3*3, maxdate) as EndDate,
DateADD(day, (-datediff(day, dateAccess, maxdate)/3+1)*3, maxdate) as StartDate,
count(reportId)
from (select *, MAX(dateAccess) over() as maxdate from @t) t
GROUP BY datediff(day, dateAccess, maxdate)/3, maxdate
答案 2 :(得分:0)
我会坚持认为最有效的方法是使用计数表。通过这种方式,您可以从日期列的索引中获得所有优势:
declare @c int = 3
;with minmax as(select min(date) as mind, max(date) as maxd from t),
tally as(select @c * (-1 + row_number() over(order by(select null))) as rn
from master..spt_values),
intervals as(select dateadd(dd, rn, mind) as f, dateadd(dd, rn + @c - 1, mind) t
from tally t cross join minmax m where dateadd(dd, rn, mind) <= maxd)
select i.f as [from], i.t as [to], count(*) as reeports
from intervals i
join t on t.date >= i.f and t.date <= i.t
group by i.f, i.t
说明:minmax
从表格中选择最短日期和最长日期。
tally
生成从0到N的数字(取决于系统,但是会计算到计算间隔)。 intervals
选择生成的时间间隔。最后一部分是间隔的简单连接,以计算每个间隔的计数。