3.8.4 如何通过游标修改表中的数据

游标的主要作用是查询数据,并对数据逐行进行处理。对于游标中的数据还可以根据需要进行修改,例如修改某个列的值,或者删除某一行。在定义游标时,需要把游标定义为可以修改的形式,定义格式如下:


DECLARE

CURSOR 游标名(参数1,参数2……)

IS

SELECT语句

FOR UPDATE;


游标可以带参数,或者不带参数。SELECT语句中的FOR UPDATE子句的作用是加锁,它的功能是把游标中的数据锁定,这样可以防止其他用户同时修改这些数据。由于在并发环境中许多用户可能同时访问数据库,如果把游标打开后不希望其他用户同时修改这些数据,就需要对游标加锁,否则就会导致数据的不一致。SELECT语句中的FOR UPDATE子句就是为了在游标打开后对它进行加锁,待游标关闭时再释放锁,用这种方式可以保证用户对数据的正确访问。

对游标中的数据是逐行处理的,每次处理指针当前指向的行。在修改游标中的数据时,也是对当前行进行修改,然后将修改后的结果写入数据库。PL/SQL提供了一种修改游标当前行的机制,如果在UPDATE、DELETE语句中使用WHERE CURRENT OF子句,可以保证只对游标当前行进行修改。WHERE CURRENT OF子句将修改操作限定在游标的当前行。

例如,某部门要为员工增加工资,增加的幅度为10%,但只限于工资最低的5名员工。如果本部门员工总数不足5人,则为所有员工都增加工资。考虑用下面的PL/SQL块实现这个操作。


DECLARE

CURSOR cur_8(d_no emp.deptno%type)

IS

SELECT ename, sal, hiredate FROM emp

WHERE deptno=d_no

ORDER BY sal—保证员工按照工资从低到高的顺序排列

FOR UPDATE;

e_count integer:=0;

e cur_8%rowtype;

BEGIN

open cur_8(30);—打开游标,将部门编号30作为参数

fetch cur_8 INTO e;

while cur_8%FOUND loop

exit when e_count>=5;

UPDATE emp set sal=sal*1.1 WHERE CURRENT OF cur_8;

e_count:=e_count+1;

fetch cur_8 INTO e;

END loop;

dbms_output.put_line('增加工资的员工人数:'||e_count);

close cur_8;

END;


这个块的运行结果为:


增加工资的员工人数:5


再来考虑下面的PL/SQL块,它的功能同样是为某部门工资最低的5名员工增加工资。不过现在要用FOR循环来处理游标中的行。


DECLARE

CURSOR cur_9(d_no emp.deptno%type)

IS

SELECT ename, sal, hiredate FROM emp

WHERE deptno=d_no

ORDER BY sal—保证员工按照工资从低到高的顺序排列

FOR UPDATE;

e_count integer:=0;

BEGIN

for e in cur_9(30)loop

exit when e_count>=5;

UPDATE emp set sal=sal*1.1 WHERE CURRENT OF cur_9;—修改员工工资

e_count:=e_count+1;

END loop;

dbms_output.put_line('增加工资的员工人数:'||e_count);

END;


通过WHERE CURRENT OF子句,不仅可以修改游标的当前行,还可以删除游标的当前行,实际的结果是从数据库中删除了当前行。例如,要删除游标cur_9的当前行时,可以使用以下语句:


DELETE FROM emp WHERE CURRENT OF cur_9;