Du behøver ikke FOR LOOP
, kun en enkelt OPDATERING gør arbejdet:
UPDATE emp
SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;
Her er en demo:http://www.sqlfiddle.com/#!4/ aacc3/1
--- REDIGER ----
Jeg lagde ikke mærke til, at i det forventede output blev afd.nr. 10 opdateret til 20,
for at opdatere afd.nr.
en anden forespørgsel er nødvendig:
UPDATE emp
SET deptno = 20
WHERE deptno = 10;
---- REDIGER -----
Hvis du vil indsætte ændrede værdier i den anden tabel, så prøv en procedure med RETURNING..BULK COLLECT og 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 burde fungere, hvis du ikke skal behandle et stort antal poster i et opkald (mere end 1000 ... eller højst et par tusinde). Hvis man dept_id
kan indeholde ti tusinde og flere rækker, så kan denne procedure være langsom, fordi den vil forbruge en enorm mængde PGA-hukommelse. I et sådant tilfælde kræves en anden tilgang med masseindsamling i bidder.
-- EDIT --- hvordan man gemmer sekvensværdier -------
Jeg antager, at tabellen ændret
har 4 kolonner, som denne:
CREATE TABLE "TEST"."CHANGED"
( "DEPTNO" NUMBER,
"OLDVAL" NUMBER,
"NEWVAL" NUMBER,
"SEQ_NEXTVAL" NUMBER
) ;
og vi gemmer sekvensværdier i seq_nextval
kolonne.
I et sådant tilfælde kan proceduren se sådan ud:
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 til små datasæt -----
Ja, for små sæt data giver bulk-indsamling ikke en væsentlig forøgelse af hastigheden, og almindelig markør med for..loop er tilstrækkelig i et sådant tilfælde.
Nedenfor er et eksempel hvordan du bruger markøren sammen med opdatering, læg mærke til WHERE CURRENT OF
klausul.
Denne gang evalueres en sekvensværdi i INSERT-sætningen.
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;