【问题标题】:Calculate a sum of cumulative product over a window frame计算窗口框架上的累积乘积之和
【发布时间】:2017-06-18 18:06:24
【问题描述】:

我想估计我的季节性预测与实际数据有何不同。我有以下数据集:

day         real_revenue    historical_coeff
01/01/2017  100             1.1
01/02/2017  105             0.98
01/03/2017  109             1.05
01/04/2017  107             1.07
01/05/2017  90              1
01/06/2017  120             0.95
01/07/2017  98              0.99

01/01/2017revenue = 100 和季节性预测采用日间系数并将其应用于当前收入。所以它预测01/02/2017 的收入将是100*1.1 = 110,在 2017 年 1 月 3 日是110*0.98 = 107.8 等等。然后,预测的剩余收入将是所有预测的总和。例如,对于01/01/2017,在应用日间系数后,总和将为688.274235

对于第二天01/02/2017,我们从值105 开始。所以我们预测在01/03/2017 上我们将有105*0.98 = 102.9,然后,对于01/04/2017,我们将预测102.9*1.05 = 108.045,依此类推。预计的总剩余收入将为531.2557215

最后我想收到这样一张桌子:

day         forecasted_total_remaining_revenue
01/01/2017  688.274235
01/02/2017  531.2557
01/03/2017  ...
01/04/2017  ...
01/05/2017  ...
01/06/2017  ...
01/07/2017  ...

基本上,我需要每天累积产品的总和,即a + a*b + a*b*c + a*b*c*d + ...

一般来说可以在vertica或sql中编写这样的查询吗?

【问题讨论】:

  • 按照解释的逻辑,01/01/2017 的结果不应该是 802.18129365 吗?
  • 如果你也包括最后一个系数,你可以得到 802。在我的情况下,我描述了只有 7 天的情况,因此不使用最后一个系数。
  • “只有 7 天”是什么意思?问题没有提到这一点。
  • 如果不清楚,我很抱歉。当我们从 2017 年 1 月 1 日开始并预测到 2017 年 1 月 7 日时,我们将有 121.1133*0.95 = 115.057635。如果我们继续预测到 2017 年 1 月 8 日,那么我们将有 115.057635*0.99 = 113.9070587。但在此示例中,我使用了截至 2017 年 1 月 7 日的天数,这就是不包括最后一个值的原因。

标签: sql vertica


【解决方案1】:

您可以使用ln()exp() 得到剩余值的乘积:

select t.*,
       exp(sum(ln(historical_coeff)) over (order by day desc)) as factor
from t;

当然,如果historical_coeff 是每个负数或零,则表达式会更复杂。

然后,你可以取这个的累积总和,得到总和所需的整体因子:

select t.*
       real_revenue * sum(factor) over (order by day desc) * forecasted_total_remaining_revenue
from (select t.*,
             real_revenue * exp(sum(ln(historical_coeff)) over (order by day desc)) as forecasted_total_remaining_revenue
      from t
     ) t

【讨论】:

  • 您必须添加ROWS UNBOUNDED PRECEDING,因为默认的RANGE 将在有相同historical_coeff 的连续行时返回错误答案(并且效率较低)。
  • Gordon.. 我认为这不会给出所需的累积产品总和。例如。您为日期(01/01/2017)添加1.1*0.98*1.05*1.07*1*0.95*0.99,为 2017 年 2 月 1 日添加 0.98*1.05*1.07*1*0.95*0.99,依此类推......但所需的总和是 1.1+1.1*0.98+1.1*0.98*1.05+1.1*0.98*1.05*1.07+1.1*0.98*1.05*1.07*1+1.1*0.98*1.05*1.07*1*0.95+1.1*0.98*1.05*1.07*1*0.95*0.99
  • 日期01/01/2017
【解决方案2】:

在常规 SQL(此处显示的语法是 SQL Sever)中,这可以通过递归 cte 来完成(只要 DBMS 支持它们)。

with rownums as (select t.*,row_number() over(order by dt) as rn from tbl t)
,cte as (select rn,dt,real_revenue,historical_coeff,cast(real_revenue*historical_coeff as decimal(38,10)) as res 
         from rownums
         where rn=1
         union all
         select t.rn,t.dt,t.real_revenue,t.historical_coeff,cast(c.res*t.historical_coeff as decimal(38,10))
         from rownums t
         join cte c on t.rn=c.rn+1
        )
select dt,sum(res) over(order by dt desc) as forecasted_remaining_revenue
from cte 

排除最后一个系数的逻辑不清楚。这总结了从给定日期到最后一个日期的所有累积产品。

Sample Demo

【讨论】:

    【解决方案3】:

    我认为您正在寻找这样的东西(您可能想要调整间隔中的天数):

    SELECT
        day,
        SUM ( frev ) OVER ( ORDER BY day
            RANGE BETWEEN CURRENT ROW AND INTERVAL '5 DAYS' FOLLOWING
        ) AS forecasted_total_remaining_revenue
    FROM (
        SELECT
            day, 
            real_revenue * 
                EXP( SUM ( LN(historical_coeff)) OVER(
                    ORDER BY day
                    RANGE BETWEEN CURRENT ROW AND INTERVAL '5 DAYS' FOLLOWING
                    )
               ) AS frev
       FROM 
           public.t1
    ) a 
    ;
    

    【讨论】:

      猜你喜欢
      • 2019-07-01
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 2022-07-26
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      相关资源
      最近更新 更多