Sie brauchen FOR LOOP
nicht , nur ein einziges UPDATE erledigt die Arbeit:
UPDATE emp
SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;
Hier ist eine Demo:http://www.sqlfiddle.com/#!4/ aacc3/1
--- BEARBEITEN ----
Ich habe nicht bemerkt, dass in der erwarteten Ausgabe deptno 10 auf 20 aktualisiert wurde,
um deptno
zu aktualisieren eine weitere Abfrage wird benötigt:
UPDATE emp
SET deptno = 20
WHERE deptno = 10;
---- BEARBEITEN -----
Wenn Sie geänderte Werte in die andere Tabelle einfügen möchten, versuchen Sie es mit RETURNING..BULK COLLECT und 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;
/
Das Verfahren sollte funktionieren, wenn Sie keine große Anzahl von Datensätzen in einem Aufruf verarbeiten möchten (mehr als 1000 ... oder maximal einige Tausend). Wenn eine dept_id
Zehntausende und mehr Zeilen enthalten kann, kann diese Prozedur langsam sein, da sie eine große Menge an PGA-Speicher verbraucht. In einem solchen Fall ist ein anderer Ansatz mit Massensammlung in Blöcken erforderlich.
-- BEARBEITEN --- wie man Sequenzwerte speichert -------
Ich nehme an, dass sich die Tabelle changed
hat hat 4 Spalten, etwa so:
CREATE TABLE "TEST"."CHANGED"
( "DEPTNO" NUMBER,
"OLDVAL" NUMBER,
"NEWVAL" NUMBER,
"SEQ_NEXTVAL" NUMBER
) ;
und wir speichern Sequenzwerte in seq_nextval
Spalte.
In einem solchen Fall könnte die Vorgehensweise wie folgt aussehen:
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 mit Cursor für kleine Datensätze -----
Ja, bei kleinen Datensätzen führt das Massensammeln nicht zu einer signifikanten Geschwindigkeitssteigerung, und in einem solchen Fall ist ein einfacher Cursor mit for..loop ausreichend.
Unten ist ein Beispiel Wie Sie den Cursor zusammen mit Update verwenden, beachten Sie den FOR UPDATE
-Klausel, ist sie erforderlich, wenn wir planen, einen vom Cursor abgerufenen Datensatz mit WHERE CURRENT OF
zu aktualisieren -Klausel.
Dieses Mal wird ein Sequenzwert innerhalb der INSERT-Anweisung ausgewertet.
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;