4

Мне нужно рассчитать разлагающееся среднее (совокупное перемещение?) Набора значений. Последнее значение в серии составляет 50% веса, с разложившимся средним значением всех предыдущих серий, как и другой вес 50%, рекурсивно.Рекурсивное распадение среднего на сервере Sql 2012

Я придумал запрос CTE, который дает правильные результаты, но зависит от последовательного номера строки. Мне интересно, есть ли лучший способ сделать это в SQL 2012, возможно, с новыми функциями окон для Over() или что-то в этом роде?

В данных в реальном времени строки упорядочены по времени. Я могу использовать представление SQL и ROW_NUMBER() для генерации необходимого поля Row для моего подхода CTE, но если есть более эффективный способ сделать это, я хотел бы сохранить это как можно более эффективным.

У меня есть таблица с двумя столбцами: строка int и значение Float. У меня 6 значений данных выборки 1,2,3,4,4,4. Правильный результат должен быть 3,78125.

Мое решение:

;WITH items AS (
    SELECT TOP 1 
    Row, Value, Value AS Decayed 
    FROM Sample Order By Row 
    UNION ALL 
    SELECT v.Row, v.Value, Decayed * .5 + v.Value *.5 AS Decayed 
    FROM Sample v 
    INNER JOIN items itms ON itms.Row = v.Row-1 
) 
SELECT top 1 Decayed FROM items order by Row desc 

Это правильно производит 3,78125 с тестовыми данными. Мой вопрос: есть ли более эффективный и/или более простой способ сделать это в SQL 2012, или это единственный способ сделать это? Благодарю.

+0

Правильно ли рекурсивный результат CTE? В том, что первая строка распадается относительно относительно других строк? Если не удалить «iif» из моего ответа. –

+0

Это правильно. Но первая строка не особо особенная. Результат для 1 элемента - это просто значение этого элемента. Добавьте второй элемент, результат предыдущего результата - 50%, а новое значение - 50%. Добавьте третье значение, затем предыдущий результат (из первых 2 элементов) равен 50%, а третий элемент - 50%. И так до конца серии. Последний элемент всегда равен 50%, а остальные 50% - предыдущий результат до добавления последнего элемента. – DaveInMaine

+0

Хорошо, что это особенно важно, когда вы смотрите на сумму, которая в конечном итоге способствует окончательному итогу, это единственная строка, которая не в два раза больше, чем ее преемник. Потому что он не уменьшается вдвое до тех пор, пока второй ряд не вступит в игру, а вторая строка будет уменьшена вдвое. –

ответ

3

Одна из возможных альтернатив будет

WITH T AS 
(
SELECT  
Value * POWER(5E-1, ROW_NUMBER() 
        OVER (ORDER BY Row DESC) 
       /* first row decays less so special cased */ 
       -IIF(LEAD(Value) OVER (ORDER BY Row DESC) IS NULL,1,0)) 
     as x 
FROM Sample 
) 
SELECT SUM(x) 
FROM T 

SQL Fiddle

Или для обновленного вопроса с использованием 60%/40%

WITH T AS 
(
SELECT IIF(LEAD(Value) OVER (ORDER BY Row DESC) IS NULL, 1,0.6) 
     * Value 
     * POWER(4E-1, ROW_NUMBER() OVER (ORDER BY Row DESC) -1) 
     as x 
FROM Sample 
) 
SELECT SUM(x) 
FROM T 

SQL Fiddle

оба из вышеизложенного выполнить один проход через данные и может потенциально e индекс на Row INCLUDE(Value), чтобы избежать сортировки.

+0

Похоже, что это дает тот же результат для серии образцов, и с несколькими другими сериями образцов он также совпадает с моим. И, похоже, это будет намного более эффективно. Проблема только в том, что я понятия не имею, как и почему это работает :) Угадайте, мне нужно кое-что прочитать. Что, если веса были разными? Скажем, если последний элемент был взвешен на 60%, а предыдущий результат составил 40%. Будет ли этот подход по-прежнему работать? – DaveInMaine

+0

Yup, похоже, что последняя версия скрипки выше делает все правильно, даже с разным весом. Должен сказать, что я никогда бы не придумал это самостоятельно, поэтому я рад, что спросил здесь. Если оценки «Query Cost» Management Studio точны, ваше решение в два раза быстрее, чем мое. Спасибо за помощь. – DaveInMaine

Смежные вопросы