PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Adição cumulativa com base dinâmica no Postgres


Crie sua própria função agregada , que pode ser usado como função de janela.

Função de agregação especializada


É mais fácil do que se imagina:
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
);

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

Resultado exatamente como solicitado.

db<>fiddle aqui
Antigo sqlfiddle

Função de agregação genérica


Para que funcione para qualquer limite e qualquer tipo de dado (numérico) , e também 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'
);

Então, para chamar com um limite de, digamos, 110 com qualquer 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 aqui
Antigo sqlfiddle

Explicação


No seu caso, não precisamos nos defender contra NULL valores desde val está definido NOT NULL . Se NULL pode estar envolvido, defina f_sum_cap() como STRICT e funciona porque (por documentação ):

Tanto a função quanto a agregação recebem mais um argumento. Para o polimórfico variante pode ser um tipo de dados codificado ou o mesmo tipo polimórfico dos argumentos principais.

Sobre funções polimórficas:

Observe o uso de literais de string não tipados , não literais numéricos, cujo padrão seria integer !