Giả sử rằng ...
-
gwma_duration
vàduration
đượ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ộtUPDATE
. Tôi đã thay thế nó bằng một truy vấn con tương quan. Nhưng có thể được thay thế bằnglast_duration
, tương tự vớilast_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ảirank()