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;