2014-09-18 70 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;