Можете да дефинирате своя собствена обобщена функция и след това да я използвате със спецификация на прозорец, за да получите обобщения изход на всеки етап, а не една стойност.
Така агрегатът е част от състояние и функция за трансформиране за промяна на това състояние за всеки ред и по избор функция за финализиране за преобразуване на състоянието в изходна стойност. За прост случай като този трябва да е достатъчна само функция за преобразуване.
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);
което ми дава:
[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
Тези числа изглежда съвпадат с електронната таблица, която сте добавили към въпроса.
Също така можете да дефинирате функцията за предаване на алфа като параметър от израза:
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
Освен това, тази функция всъщност е толкова проста, че изобщо не е необходимо да е в plpgsql, а може да бъде просто sql функция, въпреки че не можете да се позовавате на параметри по име в един от тези:
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
$$;