Нямате нужда от FOR LOOP
, само една АКТУАЛИЗАЦИЯ върши работата:
UPDATE emp
SET comm = extra
WHERE comm IS NULL AND extra IS NOT NULL;
Ето демонстрация:http://www.sqlfiddle.com/#!4/ aacc3/1
--- РЕДАКТИРАНЕ ----
Не забелязах, че в очаквания резултат deptno 10 беше актуализирано до 20,
за актуализиране на deptno
необходима е друга заявка:
UPDATE emp
SET deptno = 20
WHERE deptno = 10;
---- РЕДАКТИРАНЕ -----
Ако искате да вмъкнете променени стойности в другата таблица, опитайте процедура с RETURNING..BULK COLLECT и 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;
/
Процедурата трябва да работи, ако няма да обработвате огромен брой записи в едно повикване (повече от 1000 ... или максимум няколко хиляди). Ако един dept_id
може да съдържа десет хиляди и повече редове, тогава тази процедура може да е бавна, тъй като ще изразходва огромно количество PGA памет. В такъв случай се изисква друг подход с групово събиранеg на парчета.
-- РЕДАКТИРАНЕ --- как да съхранявате стойности на последователност -------
Предполагам, че таблицата changed
има 4 колони, като тази:
CREATE TABLE "TEST"."CHANGED"
( "DEPTNO" NUMBER,
"OLDVAL" NUMBER,
"NEWVAL" NUMBER,
"SEQ_NEXTVAL" NUMBER
) ;
и ние ще съхраняваме стойностите на последователността в seq_nextval
колона.
В такъв случай процедурата може да изглежда така:
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;
--- РЕДАКТИРАНЕ --- версия с курсор за малки набори от данни -----
Да, за малки набори от данни масовото събиране не дава значително увеличение на скоростта и обикновен курсор с for..loop е достатъчен в такъв случай.
По-долу е пример как използвате курсора заедно с актуализацията, забележете FOR UPDATE
клауза, тя е необходима, когато планираме да актуализираме запис, извлечен от курсора, използвайки WHERE CURRENT OF
клауза.
Този път стойност на последователност се оценява в оператора 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;