sql >> Databáze >  >> RDS >> Oracle

aktualizace pomocí smyčky for v plsql

Nepotřebujete FOR LOOP , stačí jediná AKTUALIZACE:

UPDATE emp
  SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;

Zde je ukázka:http://www.sqlfiddle.com/#!4/ aacc3/1

--- UPRAVIT ----

Nevšiml jsem si, že v očekávaném výstupu bylo deptno 10 aktualizováno na 20,
pro aktualizaci deptno je potřeba další dotaz:

UPDATE emp
   SET deptno = 20
WHERE deptno = 10;



---- UPRAVIT -----

Pokud chcete vložit změněné hodnoty do druhé tabulky, zkuste postup s RETURNING..BULK COLLECT a FORALL:

CREATE OR REPLACE PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
      changed_buff changed_table_type;
BEGIN
      SELECT deptno, comm, extra BULK COLLECT INTO changed_buff
      FROM emp
      WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
      FOR UPDATE;
      UPDATE emp
      SET comm = extra
      WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
      FORALL i IN 1 .. changed_buff.count
        INSERT INTO changed VALUES changed_buff( i );
END;
/

Postup by měl fungovat, pokud nebudete zpracovávat velké množství záznamů v jednom hovoru (více než 1000 ... nebo maximálně několik tisíc). Pokud jeden dept_id může obsahovat deset tisíc a více řádků, pak může být tento postup pomalý, protože spotřebovává obrovské množství paměti PGA. V takovém případě je vyžadován jiný přístup s hromadným shromažďováním po částech.

-- UPRAVIT --- jak uložit sekvenční hodnoty -------

Předpokládám, že se tabulka changed má 4 sloupce, jako je tento:

  CREATE TABLE "TEST"."CHANGED" 
   (    "DEPTNO" NUMBER, 
        "OLDVAL" NUMBER, 
        "NEWVAL" NUMBER, 
        "SEQ_NEXTVAL" NUMBER 
   ) ;

a hodnoty sekvence uložíme do seq_nextval sloupec.

V takovém případě může postup vypadat takto:

create or replace 
PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
      changed_buff changed_table_type;
BEGIN
      SELECT deptno, comm, extra, sequence_name.nextval 
        BULK COLLECT INTO changed_buff
        FROM emp
        WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
        FOR UPDATE;
      UPDATE emp
        SET comm = extra
        WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
      FORALL i IN 1 .. changed_buff.count
        INSERT INTO changed VALUES changed_buff( i );
END;



--- UPRAVIT --- verze s kurzorem pro malé sady dat -----

Ano, pro malé soubory dat hromadné shromažďování nepřináší výrazné zvýšení rychlosti a v takovém případě stačí obyčejný kurzor s for..loop.
Níže je příklad jak používat kurzor spolu s aktualizací, všimněte si FOR UPDATE klauzule, je vyžadována, když plánujeme aktualizovat záznam načtený z kurzoru pomocí WHERE CURRENT OF klauzule.
Tentokrát je sekvenční hodnota vyhodnocena v rámci příkazu INSERT.

create or replace 
PROCEDURE pro_cedure( p_dept_id number  ) 
IS
      CURSOR mycursor IS 
         SELECT deptno, comm, extra
         FROM emp
         WHERE comm IS NULL AND extra IS NOT NULL 
               AND deptno = p_dept_id
         FOR UPDATE;    
BEGIN
      FOR emp_rec IN  mycursor
      LOOP
         UPDATE emp 
            SET comm = extra
            WHERE CURRENT OF mycursor;
         INSERT INTO changed( deptno, oldval, newval, seq_nextval)
                VALUES( emp_rec.deptno, emp_rec.comm, 
                        emp_rec.extra, sequence_name.nextval );
      END LOOP;
END;


  1. Jak používat rownum

  2. Vnořená funkce PIPELINED

  3. Co přesně znamená M,D v desítkové soustavě (M,D)?

  4. Laravel Schema Builder mění modul úložiště