Получить значение столбца предыдущей строки в postgres не может использовать оконную функцию в UPDATE

Когда я больше или равен 3, я пытаюсь получить значение предыдущей строки этого столбца и пытаюсь использовать его в расчете текущей строки, и я пытался использовать функцию задержки, чтобы сделать это, но безуспешно, получал ошибка как «невозможно использовать оконную функцию в ОБНОВЛЕНИИ». Может ли кто-нибудь помочь мне. Спасибо!

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' ;

person user2569524    schedule 10.02.2014    source источник
comment
Вам нужно будет обернуть оконную функцию в подзапрос и выполнить обновление   -  person    schedule 10.02.2014
comment
Я не вижу никакого намека на пункт ORDER BY. Вся ваша операция - ерунда без порядка сортировки. В таблице базы данных нет естественного порядка.   -  person Erwin Brandstetter    schedule 24.02.2014


Ответы (1)


При условии, что ...

  • 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;

Правильное решение

Однако все вышеперечисленное очень неэффективно, когда вы можете сделать это в одной инструкции 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
person Erwin Brandstetter    schedule 24.02.2014