2014-09-18 71 views
7

我每小時的產品使用的表(多少次產品使用)的數據 -SQL查詢7天滾動平均值在SQL Server

ID (bigint)| ProductId (tinyint)| Date (int - YYYYMMDD) | Hour (tinyint)| UsageCount (int) 
#|1 | 20140901 | 0 | 10 
#|1 | 20140901 | 1 | 15 
#|1 | 20140902 | 5 | 25 
#|1 | 20140903 | 5 | 25 
#|1 | 20140904 | 3 | 25 
#|1 | 20140905 | 7 | 25 
#|1 | 20140906 | 10 | 25 
#|1 | 20140907 | 9 | 25 
#|1 | 20140908 | 5 | 25 
#|2 | 20140903 | 16 | 10 
#|2 | 20140903 | 13 | 115 

同樣,我有4級不同的產品使用數據(ProductId從1到4)每小時存儲在product_usage表中。正如您可以想象的那樣,隨着夜間ETL過程轉儲整個前一天的數據,它不斷增長。如果一天中的任何時間都沒有使用產品,則該表格中不會顯示該小時的記錄。同樣,如果一整天沒有使用產品,表中當天就不會有任何記錄。我需要生成一個報告,讓日常使用和過去7天滾動平均值 -

例如:

ProductId | Date | DailyUsage | RollingAverage 
1 | 20140901 | sum of usages of that day | (Sum of usages from 20140901 through 20140826)/7 
1 | 20140901 | sum of usages of that day | (Sum of usages from 20140901 through 20140826)/7 
1 | 20140902 | sum of usages of that day | (Sum of usages from 20140902 through 20140827)/7 
2 | 20140902 | sum of usages of that day | (Sum of usages from 20140902 through 20140827)/7 

等等.. 我計劃在SQL服務器2014年創建索引視圖。你能想到一個高效的SQL查詢來做到這一點嗎?

+0

你稱之爲「滾動平均值」實際上是一個總和。 – 2014-09-18 22:10:00

回答

8

嘗試:

select x.*, 
     avg(dailyusage) over(partition by productid order by productid, date rows between 6 preceding and current row) as rolling_avg 
    from (select productid, date, sum(usagecount) as dailyusage 
      from tbl 
     group by productid, date) x 

小提琴:

http://sqlfiddle.com/#!6/f674a7/4/0

替換 「AVG(dailusage)在......」 用總和(而不是平均),如果你真的想要什麼是過去一週的總和。在你的頭銜中,你說你想得到平均分,但後來你說你想得到總和。查詢應該與其他相同,因此請使用您實際需要的。

正如Gordon指出的那樣,這基本上是過去6個產品使用日期的平均值,如果表中沒有任何產品行的天數可能會超過過去6天因爲它根本沒有用過。爲了解決這個問題,你可以使用日期表和產品表。

+0

嘿,你知道如何改寫你的sql代碼爲msql 2008嗎?我嘗試在2008年運行它,我不斷收到錯誤。 – 2015-08-27 20:06:07

+1

SQL Server 2008不支持ROWS BETWEEN語法。你需要一個稍微不同的方法,例如http://stackoverflow.com/questions/26618353/t-sql-calculate-moving-average – reedstonefood 2016-06-17 10:34:31

3

如果您在某些日子可能缺少數據,則必須小心。如果我假設每天有某種產品的數據,那麼這種方法將起作用:

select p.productid, d.date, sum(usagecount), 
     sum(sum(usagecount)) over (partition by p.productid order by d.date 
            rows between 6 preceding and current row) as Sum7day 
from (select distinct productid from hourly) p cross join 
    (select distinct date from hourly) d left join 
    hourly h 
    on h.productid = p.productid and h.date = p.date 
group by p.productid, d.date;