2

Я пытаюсь рассчитать прогноз продаж на основе 3 предыдущих месяцев, которые могут быть действительными или прогнозируемыми.SQL - рассчитать средний прогноз

company_id Year Month Actuals Forecast 
    123456  2014  1   10  
    123456  2014  2   15  
    123456  2014  3   17  
    123456  2014  4     14.00 
    123456  2014  5     15.33 
    123456  2014  6     15.44 
    123456  2014  7     14.93 

Month 4 = (10+15+17)/3 
Month 5 = (15+17+14)/3 
Month 6 = (17+14+15.33)/3 
Month 7 = (14+15.33+15.44)/3 

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

Я просматриваю данные за последний год. Некоторые компании имеют, например, 2 месяца данных и других 12 месяцев и так далее.

Я искал и нашел множество различных решений, но все они учитывают только фактические данные.

Я думаю, что мне нужно сделать рекурсивный CTE, но я не могу понять это.

Пожалуйста, помогите :)

+0

Все ваши месяцы упорядочены точно так же, как в вашем примере? Т.е., если n = любой месяц, это расчет месяца просто фактические/прогнозные значения (n-1) + (n-2) + (n-3)/3? – WillardSolutions

+1

Какая у вас СУБД? Поддерживает ли он * Windowed Aggregates *, 'MIN ... OVER (ORDER BY ...)'? – dnoeth

+0

@EatPeanutButter - да и нет. Месяцами являются даты, такие как 01-01-2015 и т. Д. Я только что показал их row_number (если это имеет смысл). – exASHacto

ответ

1

Так вы хотите скользящее среднее на основе предыдущего скользящего среднего :) Я думаю, что при программировании на SQL Server всегда нужно понимать, какие задачи больше подходят для подхода на основе набора и wh Они более общие по строкам. Ваша задача, если вы спросите меня, идеально подходит для простой обработки строк за строкой. Вот пример

declare @temp table ([Month] int, Actual decimal(29, 2), Forecast decimal(29, 2)) 
declare @month int 

insert into @temp (
    [Month], Actual 
) 
select 1, 10 union all 
select 2, 15 union all 
select 3, 17 

select @month = isnull(max([Month]) + 1, 1) from @temp 

while @month <= 18 
begin 
    insert into @temp (
     [Month], Forecast 
    ) 
    select 
     @month, avg(a.value) as Forecast 
    from (
     select top 3 isnull(Actual, Forecast) as value 
     from @temp 
     order by [Month] desc 
    ) as a 

    select @month = @month + 1 
end 

select * from @temp 
+0

Отлично! Я все ближе и ближе. Я попытался настроить код, чтобы использовать его, но мне нужна дополнительная помощь. Я отредактирую свой вопрос ... Я думаю, что решение близко. – exASHacto

+0

, поэтому вы хотите рассчитать до определенного месяца или всего лишь 18 месяцев для каждой компании? Предположим, что у одной компании самые последние данные за 2014-03, а другая - на 2013-12 годы, что должно быть в результатах? –

+0

Предположим, что мы начнем с 2014-01. Если бы я получил данные только за 2014-03 и больше ничего до конца года, то 2015-01 = (11 * 0 + 10 * 1)/12 = 0,83. 2015-02 = (10 * 0 + 10 * 1 + 0,833 * 1)/12 = 0,90. Имеет ли это смысл? – exASHacto

1

В то время как я пытался ответить на ваш вопрос, я был еще один вопрос, который привел к более ответов на вопросы: Calculate forecast average using recursive CTE

Fiddle: http://sqlfiddle.com/#!6/9ac4a/12/0

WITH T AS 
(
    SELECT 1 AS [month], CAST(10 AS DECIMAL(28,2)) AS [forecast], CAST(-5 AS DECIMAL(28,2)) AS three_months_ago_forecast, CAST(9 AS decimal(28,2)) AS two_months_ago_forecast, CAST(26 AS decimal(28,2)) as one_month_ago_forecast 
    UNION ALL 
    SELECT 2,CAST(15 AS DECIMAL(28,2)), CAST(9 AS decimal(28,2)), CAST(26 AS decimal(28,2)), CAST(10 AS DECIMAL(28,2)) 
    UNION ALL 
    SELECT 3,CAST(17 AS DECIMAL(28,2)), CAST(26 AS decimal(28,2)), CAST(10 AS DECIMAL(28,2)), CAST(15 AS DECIMAL(28,2)) 
), 
LT AS -- LastForecast 
(
    SELECT * 
    FROM T 
    WHERE [month] = 3 
), 
FF AS -- Future Forecast 
(
    SELECT * 
    FROM LT 

    UNION ALL 

    SELECT 
     FF.[month] + 1 AS [month], 
     CAST((FF.forecast * 4 - FF.three_months_ago_forecast)/3 AS decimal(28,2)) AS forecast, 
     FF.two_months_ago_forecast as three_months_ago_forecast, 
     FF.one_month_ago_forecast as two_months_ago_forecast, 
     FF.forecast as one_month_ago_forecast 
    FROM FF 
    WHERE 
     FF.[month] < 12 

) 
SELECT * FROM T 
WHERE [month] < 3 
UNION ALL 
SELECT * FROM FF 
+0

Да @TT, запрос обновлен. –

+0

Спасибо за ваш ответ. Дело в том, что у меня нет прогнозов (14.00, 15.33 и т. Д.). Я хочу, чтобы код их вычислял. – exASHacto

+0

@exASHacto: ответ обновлен, вы можете проверить скрипку здесь: http://sqlfiddle.com/#!6/9ac4a/12/0 –

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