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