PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Dapatkan nilai Kolom dari baris sebelumnya di postgres tidak dapat menggunakan fungsi jendela di UPDATE

Dengan asumsi bahwa ...

  • gwma_duration dan duration seharusnya kolom yang sama dan berbeda karena kesalahan ketik.

  • Anda ingin memesan dengan kolom bernama order_column . Ganti dengan kolom Anda yang sebenarnya.

  • Kolom kunci utama Anda adalah res_id . Ganti dengan kolom Anda yang sebenarnya.

Mengoleskan lipstik pada babi:

Kode prosedur Anda diperbaiki dan ditingkatkan:

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;
  • Gunakan kursor implisit dari FOR lingkaran . Tidak perlu kursor eksplisit yang berat.

  • Jangan pernah mengutip nama bahasa plpgsql , yang merupakan pengenal, bukan string.

  • Sederhanakan logika Anda di beberapa tempat.

  • Yang terpenting , seperti yang diberitahukan oleh pesan kesalahan, Anda tidak dapat menggunakan fungsi jendela di SET klausa dari UPDATE . Saya menggantinya dengan subquery yang berkorelasi. Tapi mungkin bisa diganti dengan last_duration , analog dengan last_grp :ingat saja nilai dari iterasi terakhir.

Solusi yang tepat

Namun, semua hal di atas sangat tidak efisien bila Anda dapat melakukannya dalam tunggal UPDATE pernyataan :

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
  • Untuk lebih jelasnya:Anda bisa gunakan fungsi jendela di FROM klausa - setidaknya di Postgres versi modern.

  • Gunakan row_number() , bukan rank() agar setara dengan kode prosedur Anda.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dapatkan baris N terakhir dalam database secara berurutan?

  2. Pemantauan PostgreSQL Penting - Bagian 2

  3. Buat Alias ​​​​Secara Massal?

  4. JDBC - pilih di mana kolom NULL

  5. Bagaimana cara mendapatkan id dari baris yang dipilih oleh fungsi agregat?