代码之家  ›  专栏  ›  技术社区  ›  tblznbits

在oracle中计算滚动加权平均值

  •  2
  • tblznbits  · 技术社区  · 7 年前

    create table tbl_1 as (
        select * from (
            select trunc(sysdate - (rownum - 1)) as call_dt,
                   rownum as calls,
                   to_char(trunc(sysdate - (rownum - 1)), 'DAY') as dow
            from dual connect by rownum <= 22
        )
        where dow like '%MONDAY%'
        order by call_dt
    )
    ;
    
     call_dt  | calls | dow
    -------------------------
    17-SEP-18    22    MONDAY   
    24-SEP-18    15    MONDAY   
    01-OCT-18    8     MONDAY   
    08-OCT-18    1     MONDAY 
    

    我还有另一张表,上面有未来的日期,如下所示:

    create table tbl_2 as (
        select * from (
            select  trunc(sysdate + (rownum - 1)) as call_dt, 
                    0 as calls,
                    to_char(trunc(sysdate + (rownum - 1)), 'DAY') as dow
            from dual
            connect by rownum <= 15
        )
        where dow like '%MONDAY%'
    )
    ;
    
     call_dt  | calls | dow
    -------------------------
    15-OCT-18     0    MONDAY   
    22-OCT-18     0    MONDAY
    

    我试图把我未来的日期,附加到我的历史数据中,然后计算一个滚动加权平均值。我目前正在使用以下查询执行此操作。

    select  call_dt,
            case when calls = 0 then (
                (1 * lag1) + (0.8 * lag2) + (0.5 * lag3) + (0.3 * lag4))
                 else calls 
                 end as calls,
            dow
    from (
        select  call_dt, calls, dow,
                lag(calls, 4) OVER (partition by dow order by call_dt) as lag4,
                lag(calls, 3) OVER (partition by dow order by call_dt) as lag3,
                lag(calls, 2) OVER (partition by dow order by call_dt) as lag2,
                lag(calls, 1) OVER (partition by dow order by call_dt) as lag1
        from (
            select * from tbl_1
            union
            select * from tbl_2
        )
        order by dow, call_dt
    )
    ;
    

     call_dt  | calls | dow
    -------------------------
    17-SEP-18    22    MONDAY   
    24-SEP-18    15    MONDAY   
    01-OCT-18    8     MONDAY   
    08-OCT-18    1     MONDAY 
    15-OCT-18    46    MONDAY   
    22-OCT-18    24    MONDAY
    

    lag* 变量等于0,因此该值处于禁用状态。以下是我希望实现的目标:

     call_dt  | calls | dow
    -------------------------
    17-SEP-18    22    MONDAY   
    24-SEP-18    15    MONDAY   
    01-OCT-18    8     MONDAY   
    08-OCT-18    1     MONDAY 
    15-OCT-18    46    MONDAY   
    22-OCT-18    70    MONDAY
    

    我看着 this question ,似乎能给我想要的?但使用的窗口函数关键字对我来说是陌生的。我还看了 this tutorial ,但这些滚动平均函数似乎假定了非零项。有可能达到这些结果吗?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Ponder Stibbons    7 年前

    使用递归查询,它取最后一个 calls 作为 lag1 移动所有其他 lag 回顾过去:

    with 
      s as (
        select  rn, call_dt, calls, 
                lag(calls, 4) OVER (partition by dow order by call_dt) as lag4,
                lag(calls, 3) OVER (partition by dow order by call_dt) as lag3,
                lag(calls, 2) OVER (partition by dow order by call_dt) as lag2,
                lag(calls, 1) OVER (partition by dow order by call_dt) as lag1
        from (
            select 0 rn, tbl_1.* from tbl_1 union all
            select row_number() over (order by call_dt), tbl_2.* from tbl_2)),
      c(rn, call_dt, calls, lag1, lag2, lag3, lag4) as (
        select rn, call_dt, (1 * lag1) + (0.8 * lag2) + (0.5 * lag3) + (0.3 * lag4), 
               lag1, lag2, lag3, lag4 
          from s where rn = 1
        union all
        select s.rn, s.call_dt, (1 * c.calls) + (0.8 * c.lag1) + (0.5 * c.lag2) + (0.3 * c.lag3), 
               c.calls, c.lag1, c.lag2, c.lag3
          from s join c on c.rn+1 = s.rn)
    select * from c
    

    s -基本上是您的查询,我添加了行编号。 c CTE在哪里 rn = 1 是我们的锚,第一步。然后我们逐行添加下一步, 向右

    结果:

        RN CALL_DT          CALLS       LAG1       LAG2       LAG3       LAG4
    ------ ----------- ---------- ---------- ---------- ---------- ----------
         1 2018-10-15        21,5          1          8         15         22
         2 2018-10-22        30,8       21,5          1          8         15