Du behöver inte FOR LOOP
, bara en enda UPPDATERING fungerar:
UPDATE emp
SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;
Här är en demo:http://www.sqlfiddle.com/#!4/ aacc3/1
--- REDIGERA ----
Jag märkte inte att i den förväntade utgången uppdaterades avd 10 till 20,
för att uppdatera avdnr
en annan fråga behövs:
UPDATE emp
SET deptno = 20
WHERE deptno = 10;
---- REDIGERA -----
Om du vill infoga ändrade värden i den andra tabellen, prova en procedur med RETURNING..BULK COLLECT och 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;
/
Proceduren bör fungera om du inte ska behandla ett stort antal poster i ett samtal (mer än 1000 ... eller högst några tusentals). Om en dept_id
kan innehålla tiotusentals och fler rader, då kan denna procedur vara långsam, eftersom den kommer att förbruka en enorm mängd PGA-minne. I ett sådant fall krävs ett annat tillvägagångssätt med bulksamling i bitar.
-- REDIGERA --- hur man lagrar sekvensvärden -------
Jag antar att tabellen ändrades
har 4 kolumner, så här:
CREATE TABLE "TEST"."CHANGED"
( "DEPTNO" NUMBER,
"OLDVAL" NUMBER,
"NEWVAL" NUMBER,
"SEQ_NEXTVAL" NUMBER
) ;
och vi kommer att lagra sekvensvärden i seq_nextval
kolumn.
I ett sådant fall kan proceduren se ut så här:
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;
--- EDIT --- version med markör för små uppsättningar data -----
Ja, för små uppsättningar av data ger inte bulk insamling någon signifikant ökning av hastigheten, och vanlig markör med for..loop räcker i ett sådant fall.
Nedan är ett exempel hur du använder markören tillsammans med uppdatering, lägg märke till WHERE CURRENT OF
sats.
Den här gången utvärderas ett sekvensvärde i INSERT-satsen.
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;