sql >> Database teknologi >  >> RDS >> PostgreSQL

Kumulativ tilføjelse med dynamisk base i Postgres

Opret din egen aggregerede funktion , som kan bruges som vinduesfunktion.

Specialiseret aggregeret funktion

Det er nemmere end man skulle tro:

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

Så:

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

Resultat nøjagtigt som ønsket.

db<>fiddle her
Gamle sqlfiddle

Generisk aggregatfunktion

For at få det til at fungere for enhver tærskel og enhver (numerisk) datatype , og også tillad NULL værdier :

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

For derefter at ringe med en grænse på f.eks. 110 med en hvilken som helst numerisk 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 her
Gamle sqlfiddle

Forklaring

I dit tilfælde behøver vi ikke at forsvare os mod NULL værdier siden val er defineret NOT NULL . Hvis NULL kan være involveret, skal du definere f_sum_cap() som STRICT og det virker, fordi (pr. dokumentation ):

Både funktion og aggregeret tager et argument mere. Til polymorfe variant det kan være en hårdkodet datatype eller den samme polymorfe type som de førende argumenter.

Om polymorfe funktioner:

Bemærk brugen af ​​utypestrengede bogstaver , ikke numeriske bogstaver, som som standard ville være integer !




  1. Oracle 11g omdøb. Garanteret at være atomare?

  2. Returnerer det DISTINCT første tegn i et felt (MySQL)

  3. Få næsthøjeste løn for hver person i mysql

  4. Brug af SELECT-resultatsæt til at køre UPDATE-forespørgsel med MySQL Stored Procedures