Рассчитать скользящее средневзвешенное в оракуле - PullRequest
0 голосов
/ 08 октября 2018

У меня есть данные с подмножеством, которое выглядит примерно так:

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

Я посмотрел на этот вопрос , который, кажется, может дать мне то, что я хочу?Но используемые ключевые слова оконной функции были чужды мне.Я также посмотрел этот урок , но кажется, что эти скользящие средние функции предполагают ненулевые записи.Можно ли достичь этих результатов?

1 Ответ

0 голосов
/ 08 октября 2018

Использовать рекурсивный запрос, который принимает последний 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 - наш якорь, первый шаг.Затем мы добавляем следующие шаги строка за строкой, перемещая предыдущие значения вправо .Я думаю, что мы должны разделить результат на 4, но ты этого не сделал?Надеюсь, это поможет.

Результат:

    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
...