我有一张类似于下面的表格
UsedDate, ProductID, Count, usedBy 10/10/2017, Widgit1, 14, adr 10/10/2017, Widgit1, 20, mmg 10/10/2017, Widgit3, 5, mmg 11/10/2017, widgit2, 1, adr 11/10/2017, widgit1, 15, adr 11/10/2017, widgit2, 15, mmg 13/10/2017, widgit2, 8, adr 13/10/2017, widgit3, 5, adr 13/10/2017, widgit3, 4, mmg
现在,在两个日期(@startDate,@ endDate)之间的天数(@period)滚动期间我需要计算所使用的ProductID的不同计数,因此对于10/10它的2(widget1和widget 3)为11 / 10它的2(widget1,widget2)但滚动计数将是3以及期间的开始日期。但是有些日子可能会丢失,好像当天没有使用任何条目存储在数据库中。
通常,开始日期和结束日期相隔一年。
我意识到我可以通过
获得总数SELECT Cast (dbo.Usage.UsedDate as Date) AS UsedDate, count (distinct dbo.Usage.ProductID) AS used FROM dbo.Usage WHERE (dbo.Usage.UsedDate BETWEEN (@StartDate) AND (@EndDate)) GROUP BY Cast (dbo.Usage.UsedDate as Date)
但是,如何对滚动日期范围进行分区并获得一个日期表,其中包含不同的产品总数?
所以如果startDate是10/10/2017 endDate是13/10/2017 期限为2天
这意味着第一行将是10/10/2017和下一行10/10/2017数据+ 11/10/2017数据 然而,第三行只是2017年10月13日的数据,因为它在下一个时期如果有一个12/10/2017那么它也将在那个新时期出现
UsedDate, within_day_distinct_count, roll_distinct_count
10/10/2017 2, 2
11/10/2017 2, 3
13/10/2017 2, 2
答案 0 :(得分:1)
如果我理解你,那么所有期间都分为3部分:@startDate
之前,@StartDate
和@EndDate
之间,以及@EndDate
之后。
在您的示例中,仅显示2个句点:之间和之后。
在每个运行不同计数的时间段都必须单独计算,因此以下是所有3个时段的union all
代码:
declare @t table (UsedDate date, ProductID varchar(100), Cnt int, usedBy varchar(100));
insert into @t values
('20171010', 'Widgit1', 14, 'adr'),
('20171010', 'Widgit1', 20, 'mmg'),
('20171010', 'Widgit3', 5, 'mmg'),
('20171011', 'Widgit2', 1, 'adr'),
('20171011', 'Widgit1', 15, 'adr'),
('20171011', 'Widgit2', 15, 'mmg'),
('20171013', 'Widgit2', 8, 'adr'),
('20171013', 'Widgit3', 5, 'adr'),
('20171013', 'Widgit3', 4, 'mmg');
declare @startDate date = '20171010', @endDate date = '20171011'
select t.UsedDate,
count(distinct t.ProductId) as within_day_distinct_count,
count(distinct t1.ProductId) as roll_distinct_count
from @t t join @t t1
on t.UsedDate >= t1.UsedDate
WHERE t.UsedDate BETWEEN @StartDate AND @EndDate
and t1.UsedDate BETWEEN @StartDate AND @EndDate
group by t.UsedDate
union all
select t.UsedDate,
count(distinct t.ProductId) as within_day_distinct_count,
count(distinct t1.ProductId) as roll_distinct_count
from @t t join @t t1
on t.UsedDate >= t1.UsedDate
WHERE t.UsedDate > @EndDate
and t1.UsedDate > @EndDate
group by t.UsedDate
union all
select t.UsedDate,
count(distinct t.ProductId) as within_day_distinct_count,
count(distinct t1.ProductId) as roll_distinct_count
from @t t join @t t1
on t.UsedDate >= t1.UsedDate
WHERE t.UsedDate < @StartDate
and t1.UsedDate < @StartDate
group by t.UsedDate;
答案 1 :(得分:0)
您可以使用Tally创建日期范围。
一个好的做法是为计数表创建一个视图。
DECLARE @Usage as table (UsedDate date , ProductID varchar(10) , Count int , usedBy varchar(5))
INSERT @Usage(UsedDate, ProductID, Count, usedBy) VALUES
('20171010', 'Widgit1', 14, 'adr')
,('20171010', 'Widgit1', 20, 'mmg')
,('20171010', 'Widgit3', 5, 'mmg')
,('20171011', 'widgit2', 1, 'adr')
,('20171011', 'widgit1', 15, 'adr')
,('20171011', 'widgit2', 15, 'mmg')
,('20171013', 'widgit2', 8, 'adr')
,('20171013', 'widgit3', 5, 'adr')
,('20171013', 'widgit3', 4, 'mmg')
DECLARE @StartDate date = '20171010'
DECLARE @EndDate date = '20171013'
;WITH lv0(N) AS (SELECT 0 FROM (VALUES (1),(1))G(N))
,lv1(N) AS (SELECT 0 FROM lv0 a CROSS JOIN lv0 b) -- 4
,lv2(N) AS (SELECT 0 FROM lv1 a CROSS JOIN lv1 b) -- 16
,lv3(N) AS (SELECT 0 FROM lv2 a CROSS JOIN lv2 b) -- 256
,lv4(N) AS (SELECT 0 FROM lv3 a CROSS JOIN lv3 b) -- 65,536
,lv5(N) AS (SELECT 0 FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296
,cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5
)
,
DateRange AS (
SELECT DATEADD(day,N -1 ,@StartDate) DR
FROM cteTally where N <= DATEDIFF(Day, @StartDate , @EndDate) + 1
)
,ProductByday AS (SELECT DISTINCT
T.DR AS UsedDate,
U.ProductID used
FROM
DateRange T
LEFT JOIN @Usage U
ON
T.DR = Cast ( U.UsedDate as date)
)
SELECT Distinct A.UsedDate , Count(Distinct B.used) used from ProductByday A
LEFT JOIN ProductByday B
ON A.UsedDate >= B.UsedDate
GROUP BY
A.UsedDate
结果
UsedDate used
---------- -----------
2017-10-10 2
2017-10-11 3
2017-10-12 3
2017-10-13 3