PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Wie berechnet man einen exponentiellen gleitenden Durchschnitt auf Postgres?

Sie können Ihre eigene Aggregatfunktion definieren und sie dann mit einer Fensterspezifikation verwenden, um die Aggregatausgabe in jeder Phase anstelle eines einzelnen Werts zu erhalten.

Ein Aggregat ist also ein Stück Zustand und eine Transformationsfunktion, um diesen Zustand für jede Zeile zu ändern, und optional eine Finalisierungsfunktion, um den Zustand in einen Ausgabewert umzuwandeln. Für einen einfachen Fall wie diesen sollte eine Transformationsfunktion ausreichen.

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

das gibt mir:

[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

Diese Nummern scheinen mit der Tabelle übereinzustimmen, die Sie der Frage hinzugefügt haben.

Außerdem können Sie die Funktion so definieren, dass Alpha als Parameter aus der Anweisung übergeben wird:

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

Außerdem ist diese Funktion eigentlich so einfach, dass sie überhaupt nicht in plpgsql sein muss, sondern nur eine SQL-Funktion sein kann, obwohl Sie in einer dieser Funktionen nicht namentlich auf Parameter verweisen können:

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