sql >> データベース >  >> RDS >> PostgreSQL

pgSqlを使用して同じ列の前の行の合計をクエリする方法

    ユーザー定義の集計 を使用します

    ライブテスト: 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)
    ;
    

    ユーザー定義の集計

    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
    

    最初のパラメーター(_accumulated_b)は、列の累積値を保持します。 2番目のパラメーター(_current_b)は、現在の行の列の値を保持します。

    出力:

    擬似コードについては、B3 = A3 + MIN(0, B2)

    私はこの典型的なコードを使用しました:

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

    これはPostgresで慣用的に次のように書くことができます:

    select _current_b + least(_accumulated_b, 0)
    

    ライブテスト: 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';
    

    plpgsqlなど、アキュムレータ関数で他の言語を使用することもできます。 http://sqlfiddle.com ではplpgsql(またはおそらく$$引用符)はサポートされていないことに注意してください。 。したがって、ライブテストリンクはありませんが、これはお使いのマシンで機能します:

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

    更新

    partition byを見逃しました 、これはデータの例(11から-11に変更)です。partition bypartition by 異なる結果が得られます:

    ライブテスト: 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)
    ;
    

    出力:

    | 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. mysqlinnodbトランザクションの同時実行性

    2. ドキュメントのアップロードの制限

    3. '日付'のデフォルト値が無効です

    4. OracleSqlでの列行転置