您不需要FOR LOOP
,只需一个 UPDATE 即可完成工作:
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 内存。在这种情况下,需要另一种批量收集块的方法。
-- 编辑 --- 如何存储序列值 -------
我假设表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
子句,当我们计划更新从游标 usingWHERE 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;