Ammesso che...
-
gwma_durationedurationdovrebbero essere la stessa colonna e differire a causa di errori di battitura. -
Vuoi ordinare in base a una colonna denominata
order_column. Sostituisci con le colonne effettive. -
Le colonne della tua chiave primaria sono
res_id. Sostituisci con le colonne effettive.
Metti un po' di rossetto su un maiale:
Il tuo codice procedurale è stato riparato e migliorato:
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;
-
Usa il cursore implicito di un
FORciclo . Non c'è bisogno di un cursore esplicito ingombrante. -
Non citare mai il nome della lingua
plpgsql, che è un identificatore, non una stringa. -
Hai semplificato la tua logica in diversi punti.
-
La cosa più importante , come ti dice il messaggio di errore, non puoi usare le funzioni della finestra in un
SETclausola di unUPDATE. L'ho sostituito con una sottoquery correlata. Ma probabilmente potrebbe essere sostituito conlast_duration, analogo alast_grp:ricorda solo il valore dell'ultima iterazione.
Soluzione adeguata
Tuttavia, tutto quanto sopra è molto inefficiente quando puoi farlo in un singolo UPDATE dichiarazione :
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
-
Per essere chiari:tu puoi usa le funzioni della finestra nel
FROMclausola - almeno nelle versioni moderne di Postgres. -
Usa
row_number(), nonessere equivalente al tuo codice procedurale.rank()