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

postgresで前の行の列値を取得するUPDATEでウィンドウ関数を使用することはできません

    それを仮定すると...

    • gwma_duration およびduration 同じ列であると想定されており、タイプミスのために異なります。

    • order_columnという名前の列で並べ替えます 。実際の列に置き換えてください。

    • 主キー列はres_idです。 。実際の列に置き換えてください。

    豚に口紅を塗る:

    手続き型コードが修復および改善されました:

    CREATE OR REPLACE FUNCTION vin_calc()
      RETURNS void AS
    $func$
    DECLARE
       r res%rowtype;
       i integer := 0;
       last_grp text;
    BEGIN
    
    FOR r IN
       SELECT * FROM res
    LOOP
       IF last_grp <> r.prod_grp_nm THEN
          i := 1;
       ELSE
          i := i + 1;
       END IF;
    
       IF i < 3 THEN
          UPDATE res
          SET    duration = i - 1
          WHERE  dur = r.dur
          AND    prod_grp_nm = r.prod_grp_nm
          AND    week_end = r.week_end;
    
       ELSE
          UPDATE res r1
          SET    duration = r.dur * 0.125 + 
                (SELECT 0.875 * gwma_duration FROM res
                 WHERE order_column < r1.order_column
                 ORDER BY order_column
                 LIMIT 1
                )  -- could be replaced with last_duration, analog to last_grp
          WHERE  r1.dur = r.dur
          AND    r1.prod_grp_nm = r.prod_grp_nm
          AND    r1.week_end = r.week_end;
       END IF;
    
       last_grp := r.prod_grp_nm;
    
       END LOOP;
    END
    $func$
    LANGUAGE plpgsql;
    
    • <の暗黙カーソルを使用します。 code> FOR ループ 。扱いにくい明示カーソルは必要ありません。

    • 言語名を引用しないでくださいplpgsql 、これは文字列ではなく識別子です。

    • いくつかの場所でロジックを簡素化しました。

    • 最も重要なこと 、エラーメッセージに示されているように、 SETでウィンドウ関数を使用することはできません。 UPDATEの句 。相関サブクエリに置き換えました。ただし、おそらく last_durationに置き換えることができます。 、 last_grpに類似 :最後の反復の値を覚えておいてください。

    適切なソリューション

    ただし、単一の UPDATE で実行できる場合、上記のすべては非常に非効率的です。 ステートメント

    UPDATE res r
    SET    duration = CASE WHEN r0.rn < 3
                         THEN r0.rn - 1
                         ELSE r0.last_dur * 0.875 + r.dur * 0.125
                      END
    FROM  (
       SELECT res_id, duration
            , row_number()  OVER (PARTITION BY prod_grp_nm ORDER BY order_column) AS rn
            , lag(duration) OVER (PARTITION BY prod_grp_nm ORDER BY order_column) AS last_dur
       FROM res
       ) r0
    WHERE  r.res_id = r0.res_id
    
    • 明確にするために:あなたはできます FROMでウィンドウ関数を使用する 条項-少なくとも現代版のPostgresでは。

    • row_number()を使用します rank()ではありません 手続き型コードと同等になります。




    1. MySQLのHAVINGCOUNT(*)から削除

    2. INSERTがストアド関数でうまくいったかどうかを確認するにはどうすればよいですか?

    3. MySQLフィルターJSON_CONTAINS配列からの任意の値

    4. SELECT ...FORUPDATEの動作を理解するのに助けが必要ですデッドロックを引き起こします