sql >> Databáze >  >> RDS >> PostgreSQL

Jak dotazovat součet předchozího řádku stejného sloupce pomocí pgSql

Použijte uživatelsky definovaný agregát

Živý test:http://sqlfiddle.com/#!17/03ee7/1

DDL

CREATE TABLE t
    (grop varchar(1), month_year text, something int)
;

INSERT INTO t
    (grop, month_year, something)
VALUES
    ('a', '201901', -2),
    ('a', '201902', -4),
    ('a', '201903', -6),
    ('a', '201904', 60),
    ('a', '201905', -2),
    ('a', '201906', 9),
    ('a', '201907', 11),
    ('b', '201901', 100),
    ('b', '201902', -200),
    ('b', '201903', 300),
    ('b', '201904', -50),
    ('b', '201905', 30),
    ('b', '201906', -88),
    ('b', '201907', -86)
;

Uživatelem definovaný agregát

create or replace function negative_accum(_accumulated_b numeric, _current_b numeric)
returns numeric as
$$
    select case when _accumulated_b < 0 then
        _accumulated_b + _current_b
    else
        _current_b
    end
$$ language 'sql';

create aggregate negative_summer(numeric)
(
    sfunc = negative_accum,
    stype = numeric,
    initcond = 0
);

select  
    *, 
  negative_summer(something) over (order by grop, month_year) as result
from t

První parametr (_accumulated_b) obsahuje akumulovanou hodnotu sloupce. Druhý parametr (_current_b) obsahuje hodnotu sloupce aktuálního řádku.

Výstup:

Pokud jde o váš pseudokód B3 = A3 + MIN(0, B2)

Použil jsem tento typický kód:

select case when _accumulated_b < 0 then
    _accumulated_b + _current_b
else
    _current_b
end

To lze v Postgres zapsat idiomaticky jako:

select _current_b + least(_accumulated_b, 0)

Živý test:http://sqlfiddle.com/#!17/70fa8/1

create or replace function negative_accum(_accumulated_b numeric, _current_b numeric)
returns numeric as
$$
    select _current_b + least(_accumulated_b, 0) 
$$ language 'sql';

Můžete také použít jiný jazyk s funkcí akumulátoru, např. plpgsql. Všimněte si, že plpgsql (nebo možná cena $$) není podporováno v http://sqlfiddle.com . Takže žádný odkaz na živý test, na vašem počítači by to fungovalo:

create or replace function negative_accum(_accumulated_b numeric, _current_b numeric)
returns numeric as
$$begin
    return _current_b + least(_accumulated_b, 0);
end$$ language 'plpgsql';

AKTUALIZACE

Přehlédl jsem partition by , zde je příklad dat (změněno 11 na -11), kde bez partition by a pomocí partition by by přineslo jiné výsledky:

Živý test:http://sqlfiddle.com/#!17/87795/4

INSERT INTO t
    (grop, month_year, something)
VALUES
    ('a', '201901', -2),
    ('a', '201902', -4),
    ('a', '201903', -6),
    ('a', '201904', 60),
    ('a', '201905', -2),
    ('a', '201906', 9),
    ('a', '201907', -11), -- changed this from 11 to -11
    ('b', '201901', 100),
    ('b', '201902', -200),
    ('b', '201903', 300),
    ('b', '201904', -50),
    ('b', '201905', 30),
    ('b', '201906', -88),
    ('b', '201907', -86)
;

Výstup:

| grop | month_year | something | result_wrong | result |
|------|------------|-----------|--------------|--------|
|    a |     201901 |        -2 |           -2 |     -2 |
|    a |     201902 |        -4 |           -6 |     -6 |
|    a |     201903 |        -6 |          -12 |    -12 |
|    a |     201904 |        60 |           48 |     48 |
|    a |     201905 |        -2 |           -2 |     -2 |
|    a |     201906 |         9 |            7 |      7 |
|    a |     201907 |       -11 |          -11 |    -11 |
|    b |     201901 |       100 |           89 |    100 |
|    b |     201902 |      -200 |         -200 |   -200 |
|    b |     201903 |       300 |          100 |    100 |
|    b |     201904 |       -50 |          -50 |    -50 |
|    b |     201905 |        30 |          -20 |    -20 |
|    b |     201906 |       -88 |         -108 |   -108 |
|    b |     201907 |       -86 |         -194 |   -194 |


  1. Instalace Oracle Fusion Middleware / WebLogic Server 11g

  2. Android:SQLite šetřící pole řetězců?

  3. Jak resetovat/změnit heslo roota MySql příkazového řádku v ubuntu linux

  4. Upozornění:mysql_real_escape_string():Přístup odepřen uživateli ''@'localhost' (s použitím hesla:NE)