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

Adición acumulativa con base dinámica en Postgres

Cree su propia función agregada , que se puede utilizar como función de ventana.

Función agregada especializada

Es más fácil de lo que uno podría pensar:

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

Entonces:

SELECT *, sum_cap50(val) OVER (PARTITION BY fk
                               ORDER BY created) > 50 AS threshold_met 
FROM   test
WHERE  fk = 5;

Resultado exactamente como se solicitó.

db<>fiddle aquí
Antiguo sqlfiddle

Función agregada genérica

Para que funcione para cualquier umbral y cualquier tipo de datos (numéricos) , y también permitir NULL valores :

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

Luego, para llamar con un límite de, digamos, 110 con cualquier tipo numérico:

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 aquí
Antiguo sqlfiddle

Explicación

En su caso, no tenemos que defendernos contra NULL valores desde val se define NOT NULL . Si NULL puede estar involucrado, defina f_sum_cap() como STRICT y funciona porque (por documentación ):

Tanto la función como el agregado toman un argumento más. Para el polimórfico variante puede ser un tipo de datos codificado o el mismo tipo polimórfico que los argumentos principales.

Acerca de las funciones polimórficas:

Tenga en cuenta el uso de literales de cadena sin tipo , no literales numéricos, que por defecto serían integer !