Скользящая средняя окна в сервере sql - PullRequest
1 голос
/ 23 марта 2011

Я пытаюсь создать функцию, которая вычисляет оконную скользящую среднюю в SQLServer 2008 .Я довольно новичок в SQL, поэтому у меня возникли некоторые трудности.Данные, по которым я пытаюсь выполнить скользящее среднее, должны быть сгруппированы по дням (это все данные с метками времени), а затем к нему должно быть применено переменное окно скользящего среднего.

У меня уже есть функция, которая группирует данные по дням (и @id), которые показаны внизу.У меня есть несколько вопросов:

Было бы лучше вызвать функцию группировки внутри функции скользящего среднего или я должен сделать все это сразу?

Можно ли получить скользящее среднее для дат, введенных в функцию, но вернитесь назад n дней, чтобы начать скользящее среднее, чтобы первые n дней возвращаемых данных не былииметь 0 для их среднего? (т.е. если они хотят 7-дневное скользящее среднее с 01-08-2011 по 02-08-2011, чтобы я начал расчет скользящего среднего с 01-01-2011, чтобы первый деньу них определено есть значение?)

Я нахожусь в процессе изучения того, как сделать скользящее среднее, и знаю, что скользящее окно, кажется, лучший вариант (currentSum = prevSum + todayCount -nthDayAgoCount) / nDays , но я все еще работаю над выяснением реализации SQL этого.

У меня есть функция группировки, которая выглядит следующим образом (некоторые переменные удалены для целей видимости):

    SELECT
        'ALL' as GeogType,
        CAST(v.AdmissionOn as date) as dtAdmission,    
        CASE WHEN @id IS NULL THEN 99 ELSE v.ID END,
        COUNT(*) as nVisits
    FROM dbo.Table1 v INNER JOIN dbo.Table2 t ON v.FSLDU = t.FSLDU5
    WHERE v.AdmissionOn >= '01-01-2010' AND v.AdmissionOn < DATEADD(day,1,'02-01-2010') 
          AND v.ID = Coalesce(@id,ID)
    GROUP BY    
        CAST(v.AdmissionOn as date),
        CASE WHEN @id IS NULL THEN 99 ELSE v.ID END
    ORDER BY 2,3,4

, который возвращает таблицу следующим образом:

ALL 2010-01-01  1   103
ALL 2010-01-02  1   114
ALL 2010-01-03  1   86
ALL 2010-01-04  1   88
ALL 2010-01-05  1   84
ALL 2010-01-06  1   87
ALL 2010-01-07  1   82

РЕДАКТИРОВАТЬ: Чтобы ответить на первый вопрос, который я задал:

В итоге я создал функцию, которая объявилавременной таблицы и вставил в нее результаты функции count, затем использовал пример из user662852 для вычисления скользящего среднего.

1 Ответ

2 голосов
/ 23 марта 2011

Извлеките жестко закодированный диапазон дат из вашего запроса.Запишите результат (как ваш пример в конце) во временную таблицу (я назвал ее #visits ниже).
Попробуйте это самостоятельное соединение с временной таблицей:

 Select list.dtadmission
   , AVG(data.nvisits) as Avg
   , SUM(data.nvisits) as sum
   , COUNT(data.nvisits) as RollingDayCount
   , MIN(data.dtadmission) as Verifymindate
   , MAX(data.dtadmission)   as Verifymaxdate
 from  #visits as list 
 inner join #visits as data  
 on list.dtadmission between data.dtadmission and DATEADD(DD,6,data.dtadmission) group by list.dtadmission

РЕДАКТИРОВАТЬ: У меня не было достаточно места в комментариях, чтобы сказать это в ответ на ваш вопрос:

Мое соединение "своего рода декартово", потому что оно использует промежуточное число в ограничении соединения.Каждая запись в списке идет вразрез с любой другой записью, а затем я хочу, чтобы те, в которых дата, о которой я сообщаю, находилась между нижней границей (-7) дней и сегодняшним днем.Каждая дата данных доступна для списка даты, это ключ к вашему вопросу.Я мог бы написать условие соединения как

list.dtadmission between DATEADD(DD,-6,data.dtadmission) and data.dtadmission

Но на самом деле произошло то, что я протестировал его как

list.dtadmission between DATEADD(DD,6,data.dtadmission) and data.dtadmission

, который не возвращает записей, так как синтаксис «Между LOW и HIGH».Я нанесла на 0 записей и поменяла аргументы, вот и все.

Попробуйте следующее, посмотрите, что я имею в виду: это декартово объединение только для одной даты списка:

 SELECT 
 list.[dtAdmission] as listdate
 ,data.[dtAdmission] as datadate
 ,data.nVisits as datadata
 ,DATEADD(dd,6,list.dtadmission) as listplus6 
 ,DATEADD(dd,6,data.dtAdmission ) as datapplus6 
 from  [sandbox].[dbo].[admAvg] as list inner join [sandbox].[dbo].[admAvg] as data    
 on 
 1=1
 where list.dtAdmission = '5-Jan-2011'

Сравните это с фактическим условием соединения

 SELECT 
      list.[dtAdmission] as listdate
      ,data.[dtAdmission] as datadate
      ,data.nVisits as datadata
      ,DATEADD(dd,6,list.dtadmission) as listplus6 
      ,DATEADD(dd,6,data.dtAdmission ) as datapplus6
from  [sandbox].[dbo].[admAvg] as list   inner join [sandbox].[dbo].[admAvg] as data    
on 
list.dtadmission between data.dtadmission and DATEADD(DD,6,data.dtadmission)
where list.dtAdmission = '5-Jan-2011'

Посмотрите, как дата списка находится между datadate и dataplus6 во всех записях?

...