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;