2016-02-02 85 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; 

小提琴: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

預期輸出是我的問題中的第一個表格:月份和預測。 因此,基本上我只有前3個月的價值(Actuals),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

消息8120,級別16,狀態1,行1 列'cte.month'在選擇列表中無效,因爲它不包含在聚合函數或GROUP BY子句中。 –

+0

@JesúsLópez - 立即查詢 –