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 server 2014. Можете ли вы придумать эффективный SQL-запрос для этого?

2 ответов


попробуй:

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) over...."с суммой (а не avg), если то, что вы действительно хотите, - это сумма за прошлую неделю. В своем названии вы говорите, что хотите среднее, но позже вы говорите, что хотите сумму. Запрос должен быть таким же, кроме этого, поэтому используйте то, что вы действительно хотите.

Как было указано Гордоном, это в основном в среднем за последние 6 дат, когда продукт использовался, что может быть больше, чем просто за последние 6 дней, если есть дни без каких-либо строк для этого продукта на столе, потому что он не использовался вообще. Чтобы обойти это, вы можете использовать таблицу дат и таблицу продуктов.


вы должны быть осторожны, если вы можете отсутствовать данные в некоторые дни. Если я предполагаю, что есть данные для какого-то продукта на каждый день, то этот подход будет работать:

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;