sql >> Database teknologi >  >> RDS >> PostgreSQL

Hent kolonneværdi for forrige række i postgres kan ikke bruge vinduesfunktionen i UPDATE

Forudsat at ...

  • gwma_duration og varighed formodes at være den samme kolonne og afvige på grund af tastefejl.

  • Du vil bestille efter en kolonne med navnet order_column . Erstat med dine faktiske kolonne(r).

  • Dine primære nøglekolonner er res_id . Erstat med dine faktiske kolonne(r).

Sæt noget læbestift på en gris:

Din procedurekode er repareret og forbedret:

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;
  • Brug den implicitte markør på en FOR sløjfe . Intet behov for uhåndterlig eksplicit markør.

  • Citér aldrig sprognavnet plpgsql , som er en identifikator, ikke en streng.

  • Forenklet din logik flere steder.

  • Vigtigst , som fejlmeddelelsen fortæller dig, kan du ikke bruge vinduesfunktioner i et SET klausul af en OPDATERING . Jeg erstattede det med en korreleret underforespørgsel. Men kunne sandsynligvis erstattes med last_duration , analog til last_grp :husk blot værdien fra den sidste iteration.

Korrekt løsning

Men alt ovenstående er meget ineffektivt, når du kan gøre det i en enkelt OPDATERING erklæring :

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
  • For at være tydelig:du kan brug vinduesfunktioner i FROM klausul - i hvert fald i moderne versioner af Postgres.

  • Brug row_number() , ikke rank() at svare til din procedurekode.




  1. Fejlkode:1062. Dubleret indtastning '1' for nøglen 'PRIMÆR'

  2. Hvordan kan jeg erstatte alle nøglefelter i en streng med erstatningsværdier fra en tabel i T-SQL?

  3. SQL Server:vælg de nyeste rækker, hvis sum matcher en værdi

  4. SQL Server seneste versioner, udgaver og SQL Server-historik