sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo calcular un promedio móvil exponencial en postgres?

Puede definir su propia función agregada y luego usarla con una especificación de ventana para obtener la salida agregada en cada etapa en lugar de un solo valor.

Entonces, un agregado es una parte del estado y una función de transformación para modificar ese estado para cada fila y, opcionalmente, una función de finalización para convertir el estado en un valor de salida. Para un caso simple como este, solo una función de transformación debería ser suficiente.

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);

lo que me da:

[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

Estos números parecen coincidir con la hoja de cálculo que agregó a la pregunta.

Además, puede definir la función para pasar alfa como un parámetro de la instrucción:

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

Además, esta función es realmente tan simple que no necesita estar en plpgsql en absoluto, pero puede ser solo una función sql, aunque no puede hacer referencia a los parámetros por su nombre en uno de esos:

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
$$;