PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come calcolare una media mobile esponenziale su postgres?

Puoi definire la tua funzione di aggregazione e quindi utilizzarla con una specifica della finestra per ottenere l'output aggregato in ogni fase anziché un singolo valore.

Quindi un aggregato è un pezzo di stato e una funzione di trasformazione per modificare quello stato per ogni riga e, facoltativamente, una funzione di finalizzazione per convertire lo stato in un valore di output. Per un caso semplice come questo, dovrebbe essere sufficiente solo una funzione di trasformazione.

create function ema_func(numeric, numeric) returns numeric
  language plpgsql as $$
declare
  alpha numeric := 0.5;
begin
  -- uncomment the following line to see what the parameters mean
  -- raise info 'ema_func: % %', $1, $2;
  return case
              when $1 is null then $2
              else alpha * $2 + (1 - alpha) * $1
         end;
end
$$;
create aggregate ema(basetype = numeric, sfunc = ema_func, stype = numeric);

che mi dà:

[email protected]@[local] =# select x, ema(x, 0.1) over(w), ema(x, 0.2) over(w) from data window w as (order by n asc) limit 5;
     x     |      ema      |      ema      
-----------+---------------+---------------
 44.988564 |     44.988564 |     44.988564
   39.5634 |    44.4460476 |    43.9035312
 38.605724 |   43.86201524 |   42.84396976
 38.209646 |  43.296778316 |  41.917105008
 44.541264 | 43.4212268844 | 42.4419368064

Questi numeri sembrano corrispondere al foglio di lavoro che hai aggiunto alla domanda.

Inoltre, puoi definire la funzione per passare alpha come parametro dall'istruzione:

create or replace function ema_func(state numeric, inval numeric, alpha numeric)
  returns numeric
  language plpgsql as $$
begin
  return case
         when state is null then inval
         else alpha * inval + (1-alpha) * state
         end;
end
$$;

create aggregate ema(numeric, numeric) (sfunc = ema_func, stype = numeric);

select x, ema(x, 0.5 /* alpha */) over (order by n asc) from data

Inoltre, questa funzione è in realtà così semplice che non ha bisogno di essere in plpgsql, ma può essere solo una funzione sql, anche se non puoi fare riferimento ai parametri per nome in uno di quelli:

create or replace function ema_func(state numeric, inval numeric, alpha numeric)
  returns numeric
  language sql as $$
select case
       when $1 is null then $2
       else $3 * $2 + (1-$3) * $1
       end
$$;