PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Nhận giá trị cột của hàng trước đó trong postgres không thể sử dụng chức năng cửa sổ trong CẬP NHẬT

Giả sử rằng ...

  • gwma_durationduration được cho là cùng một cột và khác nhau do lỗi chính tả.

  • Bạn muốn đặt hàng theo cột có tên order_column . Thay thế bằng (các) cột thực tế của bạn.

  • Các cột khóa chính của bạn là res_id . Thay thế bằng (các) cột thực tế của bạn.

Tô chút son cho lợn:

Mã thủ tục của bạn đã được sửa chữa và cải thiện:

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;
  • Sử dụng con trỏ ngầm của FOR vòng lặp . Không cần con trỏ rõ ràng khó sử dụng.

  • Không bao giờ trích dẫn tên ngôn ngữ plpgsql , là một số nhận dạng, không phải là một chuỗi.

  • Đơn giản hóa logic của bạn ở một số nơi.

  • Quan trọng nhất , như thông báo lỗi cho bạn biết, bạn không thể sử dụng các chức năng cửa sổ trong SET mệnh đề của một UPDATE . Tôi đã thay thế nó bằng một truy vấn con tương quan. Nhưng có thể được thay thế bằng last_duration , tương tự với last_grp :chỉ cần nhớ giá trị từ lần lặp cuối cùng.

Giải pháp thích hợp

Tuy nhiên, tất cả những điều trên đều rất kém hiệu quả khi bạn có thể thực hiện nó trong một UPDATE duy nhất tuyên bố :

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
  • Nói rõ hơn:bạn có thể sử dụng các chức năng cửa sổ trong FROM mệnh đề - ít nhất là trong các phiên bản hiện đại của Postgres.

  • Sử dụng row_number() , không phải rank() tương đương với mã thủ tục của bạn.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Lập chỉ mục SQL trên varchar

  2. PostgreSQL sử dụng pg_trgm chậm hơn sau đó quét toàn bộ

  3. mã trả về psql nếu không tìm thấy hàng nào

  4. Lỗi postgres khi cập nhật dữ liệu cột

  5. Cách so sánh các mảng trong PostgreSQL