使用游标PL SQL匿名块进行多行更新

时间:2017-09-22 16:07:35

标签: sql oracle plsql rdbms

如何编写PL SQL块以一次更新多行。方案是,有两个表TABLE1,TABLE2都有一个公共列COLUMN1。在匿名块中,光标在TABLE1上定义。

首次运行块时,即v_run:=1v_offset:=2,前两行将位于光标中。在第二次运行块v_run:=2时,TABLE1中的下两行将在光标中,依此类推。

示例代码中的v_SPECIAL_VARIABLE应该是这样的 在第一次运行即v_run:=1时,在光标中提取前两行(第1,2行),COLUMN2中相应的TABLE2值更新为'N'并且TABLE2中的其余行已更新为'n'

在第二次运行即v_run:=2下,从光标中的TABLE1获取两行(第3,4行),并在COLUMN2中提取相应的TABLE2值已更新为'N'TABLE2中的其余行已更新为'n'

在第三次运行即v_run:=3下,从光标中的TABLE1获取两行(第5行),并在COLUMN2中提取相应的TABLE2值已更新为'N'TABLE2中的其余行已更新为'n'

表1包含

id | COLUMN1     | total
-------------------------
 1 | 1256480     | 5
 2 | 1256481     | 3
 3 | 1256482     | 2
 4 | 1256483     | 1
 5 | 1256484     | 3
 6 | 1256485     | 2
 7 | 1256486     | 1
 8 | 1256487     | 3

表2包含

   | COLUMN1     | column2
-------------------------
  | 1256480     | N
  | 1256481     | N
  | 1256482     | N
  | 1256483     | N
  | 1256484     | N
  | 1256485     | n
  | 1256486     | n
  | 1256487     | n

示例代码

declare
v_offset number:=2;
v_run    number:=1;
cursor curv1 is
select column1 from 
(select rownum rowcol,column1 from table1)
where rowcol between (v_run-1)*v_offset+1 and v_offset*v_run;
begin

open curv1 ;
fetch curv1 into v_SPECIAL_VARIABLE
----- first update
update table2 set column2='N' where
column1=(' ALL the values in v_SPECIAL_VARIABLE');
----- second update
update table2 set column2='n' where
column1 not in (' ALL the values in v_SPECIAL_VARIABLE');
close curv1 ;
end;

2 个答案:

答案 0 :(得分:1)

游标设计为一次处理一行。如果您想要一组值use a collection,而不是光标。

你有没有考虑过没有游标或多个陈述?

declare
  v_offset number:=2;
  v_run    number:=1;
begin

  -- one update
  update table2 set column2= CASE WHEN 
    rowcol between (v_run-1)*v_offset+1 and v_offset*v_run
    THEN 'N' ELSE 'n' END
  ;

end;

如果性能问题,您还需要添加where子句,每次只更新必要的4行,而不是表中的所有行。

答案 1 :(得分:1)

迭代游标并逐行更新是性能不佳的一个方法。尽可能摆脱游标,如:

declare
  v_offset number:=2;
  v_run    number:=1;
begin
  -- First update

  UPDATE TABLE2
    SET COLUMN2 = 'N'
    WHERE COLUMN1 IN (SELECT DISTINCT COLUMN1
                        FROM TABLE1
                        WHERE ROWCOL BETWEEN (v_run-1)*v_offset+1
                                         AND v_offset*v_run);

  -- Second update

  UPDATE TABLE2
    SET COLUMN2 = 'n'
    WHERE COLUMN1 NOT IN (SELECT DISTINCT COLUMN1
                            FROM TABLE1
                            WHERE ROWCOL BETWEEN (v_run-1)*v_offset+1
                                             AND v_offset*v_run);
end;

请注意,在这种情况下,更新可以简化为:

declare
  v_offset number:=2;
  v_run    number:=1;
begin
  -- Second update

  UPDATE TABLE2
    SET COLUMN2 = 'n'
    WHERE COLUMN1 IS NOT NULL;

  UPDATE TABLE2
    SET COLUMN2 = 'N'
    WHERE COLUMN1 IN (SELECT DISTINCT COLUMN1
                        FROM TABLE1
                        WHERE ROWCOL BETWEEN (v_run-1)*v_offset+1
                                         AND v_offset*v_run);
end;

祝你好运。