当i大于或等于3时,我试图获取该列的前一行值并尝试在当前行计算中使用它并且我尝试使用Lag函数这样做但是没有成功,得到的错误是“无法在UPDATE中使用窗口函数”。有人可以帮助我。谢谢!
CREATE OR REPLACE FUNCTION vin_calc() RETURNS text AS
$BODY$
DECLARE
r res%rowtype;
i integer default 0;
x text;
curs2 CURSOR FOR SELECT * FROM res;
BEGIN
open curs2;
-- FOR r IN curs2
LOOP
FETCH curs2 INTO r;
exit when not found;
if(x!=r.prod_grp_nm) then
i:=0;
end if;
i:= i+1;
if (i=1) then
update res set duration =0 where
dur=r.dur and prod_grp_nm=r.prod_grp_nm and week_end=r.week_end;
elsif(i=2) then
update res set duration =1 where
dur=r.dur and prod_grp_nm=r.prod_grp_nm and week_end=r.week_end;
elsif(i>=3) then
update res set gwma_duration =0.875*lag(res.duration,1) over()+(0.125*r.dur) where
dur=r.dur and prod_grp_nm=r.prod_grp_nm and week_end=r.week_end;
end if ;
x:=r.prod_grp_nm;
END LOOP;
RETURN 'yes';
END
$BODY$
LANGUAGE 'plpgsql' ;
答案 0 :(得分:0)
假设......
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;
使用FOR
loop的隐式光标。不需要笨拙的显式游标。
永远不要引用语言名plpgsql
,这是一个标识符,而不是字符串。
在几个地方简化了你的逻辑。
最重要的是,正如错误消息所示,您无法在SET
的{{1}}子句中使用窗口函数。我用相关的子查询替换它。但可能会被替换为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
子句中的窗口函数 - 至少在现代版本的Postgres中。
使用row_number()
,而非 等同于您的程序代码。FROM