sql >> Database >  >> RDS >> PostgreSQL

Cumulatief optellen met dynamische basis in Postgres

Maak uw eigen verzamelfunctie , die als vensterfunctie kan worden gebruikt.

Gespecialiseerde aggregatiefunctie

Het is makkelijker dan je zou denken:

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

Dan:

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

Resultaat precies zoals gevraagd.

db<>fiddle hier
Oude sqlfiddle

Algemene aggregatiefunctie

Om het te laten werken voor alle drempels en elk (numeriek) gegevenstype , en ook sta NULL toe waarden :

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

Om vervolgens te bellen met een limiet van bijvoorbeeld 110 met een willekeurig numeriek type:

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 hier
Oude sqlfiddle

Uitleg

In jouw geval hoeven we ons niet te verdedigen tegen NULL waarden sinds val is gedefinieerd NOT NULL . Als NULL betrokken kan zijn, definieer f_sum_cap() als STRICT en het werkt omdat (per documentatie ):

Zowel functie als aggregaat hebben nog een argument. Voor de polymorfe variant kan het een hard gecodeerd gegevenstype zijn of hetzelfde polymorfe type als de leidende argumenten.

Over polymorfe functies:

Let op het gebruik van niet-getypte letterlijke tekenreeksen , geen numerieke letterlijke waarden, die standaard integer . zouden zijn !




  1. RETURNING veroorzaakt fout:ontbrekende FROM-clausule voor tabel

  2. Voer PDO uit met een array die null-waarden bevat

  3. Waarom wordt mysql_escape_string ten zeerste afgeraden?

  4. Een tabel maken op basis van een query met een andere tabelruimte (Oracle SQL)