在postgres中计算过去3个月的月预测

时间:2016-11-23 05:09:35

标签: postgresql

我有一个名为预测的表格,我们存储未来6个月所有产品的预测。例如,当我们在11月时,我们创建了12月,1月,2月,3月,4月和5月的预测。预测表看起来像下面的那个

+----------------+---------------+--------------+----------+
| product_number | forecasted_on | forecast_for | quantity |
+----------------+---------------+--------------+----------+
| Prod 1         | 2016-11-01    | 2016-12-01   |      100 |
| Prod 1         | 2016-11-01    | 2017-01-01   |      200 |
| Prod 1         | 2016-11-01    | 2017-02-01   |      300 |
| Prod 1         | 2016-11-01    | 2017-03-01   |      400 |
| Prod 1         | 2016-11-01    | 2017-04-01   |      500 |
| Prod 1         | 2016-11-01    | 2017-05-01   |      600 |
+----------------+---------------+--------------+----------+

表中包含产品编号列表和创建预测的日期,即forecasted_on和创建预测的月份以及预测数量。

每个月都会在接下来的6个月内添加数据。因此,当预测为2016年12月1日时,将在1月至6月期间创建预测。

我正在尝试制作一份报告,说明过去3个月的总预测情况如何变化。像这样的东西

+------------+----------------+---------------+----------------+
|            | 0 months prior | 1 month prior | 2 months prior |
+------------+----------------+---------------+----------------+
| 2016-12-01 |            200 |           150 |            250 |
| 2017-01-01 |            300 |           250 |            150 |
| 2017-02-01 |            100 |           150 |            100 |
+------------+----------------+---------------+----------------+

目前我在rails中使用了大量重复代码来生成此表。我想看看是否有更简单的方法直接使用SQL查询。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

使用PIVOT查询:

select forecast_for, 
       sum( case when forecasted_on + interval '1' month = forecast_for 
            then quantity end ) q_0,
       sum( case when forecasted_on + interval '2' month = forecast_for 
            then quantity end ) q_1,
       sum( case when forecasted_on + interval '3' month = forecast_for 
            then quantity end ) q_2,
       sum( case when forecasted_on + interval '4' month = forecast_for 
            then quantity end ) q_3,
       sum( case when forecasted_on + interval '5' month = forecast_for 
            then quantity end ) q_4,
       sum( case when forecasted_on + interval '6' month = forecast_for 
            then quantity end ) q_5
from Table1
group by forecast_for
order by 1
;

演示:http://sqlfiddle.com/#!15/30e5e/1

|               forecast_for |    q_0 |    q_1 |    q_2 |    q_3 |    q_4 |    q_5 |
|----------------------------|--------|--------|--------|--------|--------|--------|
| December, 01 2016 00:00:00 |    100 | (null) | (null) | (null) | (null) | (null) |
|  January, 01 2017 00:00:00 | (null) |    200 | (null) | (null) | (null) | (null) |
| February, 01 2017 00:00:00 | (null) | (null) |    300 | (null) | (null) | (null) |
|    March, 01 2017 00:00:00 | (null) | (null) | (null) |    400 | (null) | (null) |
|    April, 01 2017 00:00:00 | (null) | (null) | (null) | (null) |    500 | (null) |
|      May, 01 2017 00:00:00 | (null) | (null) | (null) | (null) | (null) |    600 |

答案 1 :(得分:0)

假设(product_number, forcast_on, forcasted_for)是唯一的(因此不需要聚合),那么这应该可以完成这项工作:

WITH forecast_dates AS (
    SELECT DISTINCT product_number, forcast_for
    FROM forecasts
)
SELECT
  fd.forcast_for AS "forecast for",
  m1.quantity    AS "one month prior",
  m2.quantity    AS "two months prior",
  m3.quantity    AS "three months prior"
FROM forecast_dates fd
  LEFT JOIN forecasts m1 ON fd.forcast_for = m1.forcast_for AND fd.forcast_for = m1.forcasted_on + INTERVAL '1 month'
  LEFT JOIN forecasts m2 ON fd.forcast_for = m2.forcast_for AND fd.forcast_for = m2.forcasted_on + INTERVAL '2 month'
  LEFT JOIN forecasts m3 ON fd.forcast_for = m3.forcast_for AND fd.forcast_for = m3.forcasted_on + INTERVAL '3 month'
WHERE fd.product_number = 'Prod 1'
ORDER BY fd.forcast_for;