Utwórz własną funkcję agregującą , która może być używana jako funkcja okna.
Specjalistyczna funkcja agregująca
To prostsze niż mogłoby się wydawać:
CREATE OR REPLACE FUNCTION f_sum_cap50 (numeric, numeric)
RETURNS numeric LANGUAGE sql AS
'SELECT CASE WHEN $1 > 50 THEN 0 ELSE $1 END + $2';
CREATE AGGREGATE sum_cap50 (numeric) (
sfunc = f_sum_cap50
, stype = numeric
, initcond = 0
);
Następnie:
SELECT *, sum_cap50(val) OVER (PARTITION BY fk
ORDER BY created) > 50 AS threshold_met
FROM test
WHERE fk = 5;
Wynik dokładnie taki, jak zażądano.
db<>fiddle tutaj
Stary sqlfiddle
Ogólna funkcja agregująca
Aby działało dla dowolnych progów i dowolny (numeryczny) typ danych , a także zezwalaj na NULL
wartości :
CREATE OR REPLACE FUNCTION f_sum_cap (anyelement, anyelement, anyelement)
RETURNS anyelement
LANGUAGE sql STRICT AS
$$SELECT CASE WHEN $1 > $3 THEN '0' ELSE $1 END + $2;$$;
CREATE AGGREGATE sum_cap (anyelement, anyelement) (
sfunc = f_sum_cap
, stype = anyelement
, initcond = '0'
);
Następnie, aby zadzwonić z limitem, powiedzmy 110, z dowolnym typem liczbowym:
SELECT *
, sum_cap(val, '110') OVER (PARTITION BY fk
ORDER BY created) AS capped_at_110
, sum_cap(val, '110') OVER (PARTITION BY fk
ORDER BY created) > 110 AS threshold_met
FROM test
WHERE fk = 5;
db<>fiddle tutaj
Stary sqlfiddle
Wyjaśnienie
W Twoim przypadku nie musimy się bronić przed NULL
wartości od val
jest zdefiniowany NOT NULL
. Jeśli NULL
może być zaangażowany, zdefiniuj f_sum_cap()
jako STRICT
i działa, ponieważ (zgodnie z dokumentacją
):
Zarówno funkcja, jak i agregacja przyjmują jeszcze jeden argument. Dla polimorficzny wariant może to być typ danych zakodowany na stałe lub ten sam typ polimorficzny, co główne argumenty.
O funkcjach polimorficznych:
Zwróć uwagę na użycie niewpisanych literałów ciągu , a nie literały numeryczne, które domyślnie byłyby integer
!