2017-05-30 125 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