PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Ajout cumulatif avec base dynamique dans Postgres

Créer votre propre fonction d'agrégation , qui peut être utilisé comme fonction de fenêtre.

Fonction d'agrégation spécialisée

C'est plus simple qu'on ne le pense :

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

Ensuite :

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

Résultat exactement comme demandé.

db<>violon ici
Ancien sqlfiddle

Fonction d'agrégation générique

Pour que cela fonctionne pour tous les seuils et tout type de données (numérique) , et aussi autoriser NULL valeurs :

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

Ensuite, pour appeler avec une limite de, disons, 110 avec n'importe quel type numérique :

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<>violon ici
Ancien sqlfiddle

Explication

Dans votre cas, nous n'avons pas à nous défendre contre NULL valeurs depuis val est défini NOT NULL . Si NULL peut être impliqué, définissez f_sum_cap() comme STRICT et cela fonctionne parce que (par documentation ):

La fonction et l'agrégat prennent tous deux un argument de plus. Pour le polymorphe variante, il peut s'agir d'un type de données codé en dur ou du même type polymorphe que les arguments principaux.

À propos des fonctions polymorphes :

Notez l'utilisation de littéraux de chaîne non typés , et non des littéraux numériques, qui seraient par défaut integer !