2017-05-30 90 views
0

我有一个销售表,它包含不同商店的销售数据以及时间,比方说一天之内,我们已经完成了一万条交易,然后我需要要查找该特定生意日期每15分钟的总销售额,请记住例如:如果在中午12:00至下午12:15之间没有销售,那么它应该为零或为零。按照时间间隔每15分钟一组的销售数据

在一天中,我们有24小时,所以它意味着在15分钟的间隔96列。

Sales Table: 

SiteName   Time   Amount  BusinessDate 
---------------------------------------------------------- 
A    7:01:02 AM  20   2017-01-02 
A    7:03:22 AM  25   2017-01-02 
A    7:05:03 AM  33   2017-01-02 
A    7:11:02 AM  55   2017-01-02 
A    7:13:05 AM  46   2017-01-02 
A    7:17:02 AM  21   2017-01-02 
A    8:01:52 AM  18   2017-01-02 
A    8:55:42 AM  7    2017-01-02 
A    8:56:33 AM  7    2017-01-02 
A    8:58:55 AM  31   2017-01-02 

我怎样才能做到这一点?

+1

我会用一个符合表这一点。如果你想要更多的细节,你需要提供给我们。这里是一个开始的好地方。 http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/ –

+1

您将需要创建时间间隔表或者预先或作为递归在CTE中查询,然后加入。 –

+0

@ PM77-1我真的很感激,如果你能够提供给我一个高级语法,以确保如何开始 – 3MRAN

回答

2

动态实施例

Declare @SQL varchar(max) = Stuff((Select ',' + QuoteName(T) 
            From (Select Top 96 T=format(DateAdd(Minute,(Row_Number() Over (Order By (Select null))-1)*15,0),'HH:mm') From master..spt_values n1) A 
            Order by 1 
            For XML Path('')),1,1,'') 
Select @SQL = ' 
Select * 
From (
     Select [SiteName] 
       ,Col = format(DateAdd(MINUTE,(DatePart(HOUR,[Time])*60) + ((DatePart(MINUTE,[Time])/15)*15),0),''HH:mm'') 
       ,Value = [Amount] 
     From Sales 
    ) A 
Pivot (sum(Value) For [Col] in (' + @SQL + ')) p' 
Exec(@SQL); 

返回从00:00 96列到23:45

enter image description here

生成的代码

Select * 
From (
     Select [SiteName] 
       ,Col = format(DateAdd(MINUTE,(DatePart(HOUR,[Time])*60) + ((DatePart(MINUTE,[Time])/15)*15),0),'HH:mm') 
       ,Value = [Amount] 
     From Sales 
    ) A 
Pivot (sum(Value) For [Col] in ([00:00],[00:15],[00:30],[00:45],[01:00],[01:15],[01:30],[01:45],[02:00],[02:15],[02:30],[02:45],[03:00],[03:15],[03:30],[03:45],[04:00],[04:15],[04:30],[04:45],[05:00],[05:15],[05:30],[05:45],[06:00],[06:15],[06:30],[06:45],[07:00],[07:15],[07:30],[07:45],[08:00],[08:15],[08:30],[08:45],[09:00],[09:15],[09:30],[09:45],[10:00],[10:15],[10:30],[10:45],[11:00],[11:15],[11:30],[11:45],[12:00],[12:15],[12:30],[12:45],[13:00],[13:15],[13:30],[13:45],[14:00],[14:15],[14:30],[14:45],[15:00],[15:15],[15:30],[15:45],[16:00],[16:15],[16:30],[16:45],[17:00],[17:15],[17:30],[17:45],[18:00],[18:15],[18:30],[18:45],[19:00],[19:15],[19:30],[19:45],[20:00],[20:15],[20:30],[20:45],[21:00],[21:15],[21:30],[21:45],[22:00],[22:15],[22:30],[22:45],[23:00],[23:15],[23:30],[23:45])) p 
1

这是一个不使用动态SQL的选项,而不是每行96个列,每个时隙生成一行。首先,我从数据的样本表开始。现在

create table #Sales 
(SiteName nvarchar(1), 
    SaleTime time, 
    Amount decimal, 
    BusinessDate Date); 

insert into #Sales (SiteName, SaleTime, Amount, BusinessDate) 
values 
('A', '7:01:02', 20, '2017-01-02'), 
('A', '7:03:22', 25, '2017-01-02'), 
('A', '7:05:03', 33, '2017-01-02'), 
('A', '7:11:02', 55, '2017-01-02'), 
('A', '7:13:05', 46, '2017-01-02'), 
('A', '7:17:02', 21, '2017-01-02'), 
('A', '8:01:52', 18, '2017-01-02'), 
('A', '8:55:42', 7, '2017-01-02'), 
('A', '8:56:33', 7, '2017-01-02'), 
('A', '8:58:55', 31, '2017-01-02'); 

And the query which I will explain shortly 

select 
     allTimes.TimeStart, 
     allTimes.TimeEnd, 
     coalesce(count(S.Amount), 0) as NumEntries, 
     coalesce(sum(S.Amount), 0) as SumValues 
    from 
     (select 
       cast(DateAdd(minute, 15 * (timeSlots.Row -1), '2017-01-01') as time) as TimeStart, 
       cast(DateAdd(minute, 15 * timeSlots.Row, '2017-01-01') as time) as TimeEnd 
      from 
       (SELECT top 96 
         ROW_NUMBER() OVER(Order by AnyColumnInYourTable) Row 
        FROM  
         AnyTableThatHasAtLeast96Rows) timeSlots 
     ) allTimes 
      LEFT JOIN #Sales S 
       on allTimes.TimeStart <= S.SaleTime 
       AND S.SaleTime < allTimes.TimeEnd 
      AND (allTimes.TimeEnd < allTimes.TimeStart 
       OR S.SaleTime <= allTimes.TimeEnd) 
    group by 
     allTimes.TimeStart, 
     allTimes.TimeEnd 

,解释...

首先,最内层的查询结果别名 “时隙”。这可以从ANY表查询至少有96时隙增量您正在寻找,什么都不做,但返回从1到96顺序编号的结果集。

现在我们有96行,我们得到下一个外部查询别名结果为“allTimes”。这基本上做日期/时间的数学计算,并增加了15分钟的时间间隔*无论“行”数值是多少,创建所有时间段为96行。我已明确应用开始和结束时间来应用> =和<。但是这个查询只会创建明确的时间段。而且,由于我将DATEADD()组件转换为TIME,所以我开始使用固定的“Date”值 - 在本例中为2017-01-01。我所关心的只是时间本身。结果会是怎样......

TimeStart TimeEnd 
00:00:00  00:15:00 
00:15:00  00:30:00 
00:30:00  00:45:00 
... 
23:30:00  23:45:00 
23:45:00  00:00:00 -- This one is special for the JOIN clause for time 

现在,LEFT JOIN ...这是有点难一个

LEFT JOIN #Sales S 
    on allTimes.TimeStart <= S.SaleTime 
    AND S.SaleTime < allTimes.TimeEnd 
    AND (allTimes.TimeEnd < allTimes.TimeStart 
     OR S.SaleTime <= allTimes.TimeEnd) 

这里,左侧的接合部的销售将始终允许每个时隙在最终结果集中。但是,哪个插槽可以进行特定销售?销售时间必须大于或等于起始的15分钟间隔...

和..

要么...的结束时间小于开始(通过槽在23:45 - 00 :第二天早上的00)或者下一个时隙的开始。例如:08:30 - 8:45时间段的精度实际上高达8:44:xxxxx,但始终小于8:45。

通过与每个时隙一行这样的方式,我可以得到交易的数量,交易的总和,你甚至可以做到平均,最小,最大的销售活动也为寻找趋势。

1
WITH dates AS (
SELECT CAST('2009-01-01' AS datetime) 'date' 
UNION ALL 
SELECT DATEADD(mi, 15, t.date) 
    FROM dates t 
    WHERE DATEADD(mi, 15, t.date) < '2009-01-02') 
SELECT cast([date] as time) as [date] from dates 

使用上面的代码在一天的15分钟间隔内获得96列。

加入销售表与上述CTE。

1

这里递归CTE 24小时值(96行)产生15个分钟的间隔。

那么这个结果LEFT JOIN版子查询。子查询Amount按每小时15分钟的间隔进行分组。

在结果,00:00:00对应的量,它从00:00:00碰巧00:14:59

00:15:00 =从00:15:0000:29:59

00:30:00 =从00:30:0000:44:59

00:45:00 =从00:45:0000:59:59

的总和

等,每24小时

create table #Sales 
(SiteName nvarchar(1), 
    SaleTime time, 
    Amount decimal, 
    BusinessDate Date); 

insert into #Sales (SiteName, SaleTime, Amount, BusinessDate) 
values 
('A', '13:22:36', 888, '2017-01-02'), 
('A', '00:00:00', 20, '2017-01-02'), 
('A', '00:00:00', 30, '2017-01-02'), 
('A', '00:45:00', 88, '2017-01-02'), 
('A', '12:46:05', 22, '2017-01-02'), 
('A', '12:59:59', 22, '2017-01-02'), 
('A', '23:59:59', 10, '2017-01-02'); 

-- Below is actual query: 

with rec as(
    select cast('00:00:00' as time) as dt 
    union all 
    select DATEADD (mi , 15 , dt) from rec 
    where 
    dt < cast('23:45:00' as time) 
) 
select rec.dt, t1.summ from rec 
left join 
(select part, sum(Amount) as summ from (
    select *, case 
     when DATEPART (mi , SaleTime) < 15 then concat(SUBSTRING (cast(SaleTime as varchar) ,1 , 2), ':00:00') 
     when DATEPART (mi , SaleTime) between 15 and 29 then concat(SUBSTRING (cast(SaleTime as varchar) ,1 , 2), ':15:00') 
     when DATEPART (mi , SaleTime) between 30 and 44 then concat(SUBSTRING (cast(SaleTime as varchar) ,1 , 2), ':30:00') 
     else concat(SUBSTRING (cast(SaleTime as varchar) ,1 , 2), ':45:00') 
     end as part 
    from #Sales 
    where BusinessDate = '2017-01-02' 
) t 
group by part) t1 
on rec.dt = t1.part 
order by rec.dt 

rextester demo