2016-02-02 2 views
3

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

Month Actuals Forecast 
1  10  
2  15  
3  17  
4    14.00 
5    15.33 
6    15.44 
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 

Я пытался сделать это с помощью рекурсивных CTE:

;WITH cte([month],forecast) AS (
    SELECT 1,CAST(10 AS DECIMAL(28,2)) 
    UNION ALL 
    SELECT 2,CAST(15 AS DECIMAL(28,2)) 
    UNION ALL 
    SELECT 3,CAST(17 AS DECIMAL(28,2)) 
    UNION ALL 
    SELECT 
     [month]=[month]+1, 
     forecast=CAST(AVG(forecast) OVER (ORDER BY [month] ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) AS DECIMAL(28,2)) 
    FROM 
     cte 
    WHERE 
     [month]<=12 
) 
SELECT * FROM cte WHERE month<=12; 

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

Но это не работает, как и следовало ожидать, поскольку она возвращает следующий результат:

| month | forecast | 
|-------|----------| 
|  1 |  10 | 
|  2 |  15 | 
|  3 |  17 | 
|  4 | (null) | 
|  5 | (null) | 
|  6 | (null) | 
|  7 | (null) | 
|  8 | (null) | 
|  9 | (null) | 
| 10 | (null) | 
| 11 | (null) | 
| 12 | (null) | 
|  3 | (null) | 
|  4 | (null) | 
|  5 | (null) | 
|  6 | (null) | 
|  7 | (null) | 
|  8 | (null) | 
|  9 | (null) | 
| 10 | (null) | 
| 11 | (null) | 
| 12 | (null) | 
|  2 | (null) | 
|  3 | (null) | 
|  4 | (null) | 
|  5 | (null) | 
|  6 | (null) | 
|  7 | (null) | 
|  8 | (null) | 
|  9 | (null) | 
| 10 | (null) | 
| 11 | (null) | 
| 12 | (null) | 

Ожидаемый результат:

| month | forecast | 
|-------|----------| 
|  1 |  10 | 
|  2 |  15 | 
|  3 |  17 | 
|  4 | 14.00 | 
|  5 | 15.33 | 
|  6 | 15.44 | 
|  7 | 14.93 | 
|  8 | 15.23 | 
|  9 | 15.20 | 
| 10 | 15.12 | 
| 11 | 15.18 | 
| 12 | 15.17 | 

Может кто-нибудь сказать мне, что не так в этом вопросе?

+0

может обеспечить ожидаемый выход – yuvi

+0

Ожидаемый результат - первая таблица в моем вопросе: месяц и прогноз. Так что в основном у меня есть значения (Actuals) только за первые 3 месяца, в течение месяцев> 3 Мне нужно прогнозировать значение, как среднее из последних 3 значений. –

+0

Ожидаемый результат добавлен, любезно предоставлен @TT –

ответ

5

я предлагаю что-то вроде этого:

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 

Выход:

+-------+----------+---------------------------+-------------------------+------------------------+ 
| month | forecast | three_months_ago_forecast | two_months_ago_forecast | one_month_ago_forecast | 
+-------+----------+---------------------------+-------------------------+------------------------+ 
|  1 | 10.00 | -5.00      | 9.00     | 26.00     | 
|  2 | 15.00 | 9.00      | 26.00     | 10.00     | 
|  3 | 17.00 | 26.00      | 10.00     | 15.00     | 
|  4 | 14.00 | 10.00      | 15.00     | 17.00     | 
|  5 | 15.33 | 15.00      | 17.00     | 14.00     | 
|  6 | 15.44 | 17.00      | 14.00     | 15.33     | 
|  7 | 14.92 | 14.00      | 15.33     | 15.44     | 
|  8 | 15.23 | 15.33      | 15.44     | 14.92     | 
|  9 | 15.20 | 15.44      | 14.92     | 15.23     | 
| 10 | 15.12 | 14.92      | 15.23     | 15.20     | 
| 11 | 15.19 | 15.23      | 15.20     | 15.12     | 
| 12 | 15.18 | 15.20      | 15.12     | 15.19     | 
+-------+----------+---------------------------+-------------------------+------------------------+ 
2

Попробуйте

WITH cte 
    AS (SELECT * 
     FROM (VALUES (1,10,NULL), 
         (2,15,NULL), 
         (3,17,NULL), 
         (4,NULL,14.00), 
         (5,NULL,15.33), 
         (6,NULL,15.44), 
         (7,NULL,14.93)) tc (month, act, fore)) 
SELECT mon,avg(res) 
FROM cte a 
     CROSS apply (SELECT TOP 3 (COALESCE(a.act, a.fore)) AS res, 
           b.month      AS mon 
        FROM cte b 
        WHERE a.month < b.month 
        ORDER BY a.month DESC) cs 
GROUP BY mon 
ORDER BY mon 

или Sql Server 2012+ использования этого

SELECT 
    [month]=[month]+1, 
    forecast=CAST(AVG(COALESCE(act,fore)) OVER (ORDER BY [month] ROWS BETWEEN 3 PRECEDING AND CURRENT row ) AS DECIMAL(28,2)) 
FROM 
    cte 
+0

Спасибо @ VR46, можете ли вы рассказать мне, что не так с моим запросом? поскольку это мой вопрос на самом деле. –

+0

Msg 8120, уровень 16, состояние 1, строка 1 Столбец 'cte.month' недопустим в списке выбора, потому что он не содержится ни в агрегатной функции, ни в предложении GROUP BY. –

+0

@ JesúsLópez - сейчас –

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