Oracle PL/SQL开发基础(第二十五弹:操纵游标数据)

时间:2022-09-12 11:44:51

LOOP循环

如:

DECLARE
dept_row dept%ROWTYPE; --定义游标结果记录变量
CURSOR dept_cursor IS SELECT * FROM dept; --定义游标变量
BEGIN
OPEN dept_cursor;
--打开游标
LOOP --简单循环
FETCH dept_cursor INTO dept_row; --提取游标数据
EXIT WHEN dept_cursor%NOTFOUND; --退出循环的控制语句
DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
END LOOP;
CLOSE dept_cursor; --关闭游标
END;

WHILE循环

如:

DECLARE
dept_row dept%ROWTYPE; --定义游标结果记录变量
CURSOR dept_cursor IS SELECT * FROM dept; --定义游标变量
BEGIN
OPEN dept_cursor;
--打开游标
FETCH dept_cursor INTO dept_row; --提取游标数据
WHILE dept_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
FETCH dept_cursor INTO dept_row; --提取游标数据
END LOOP;
CLOSE dept_cursor; --关闭游标
END;

游标FOR循环

游标FOR循环可以省去很多代码,PL/SQL隐式地做了很多工作。
如:

DECLARE
CURSOR dept_cursor IS SELECT * FROM dept; --定义游标变量
BEGIN
FOR dept_row IN dept_cursor LOOP --在游标FOR循环中检索数据
DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);

END LOOP;
END;

还能再简单一点:

BEGIN 
FOR dept_row IN (SELECT * FROM dept) LOOP --在游标FOR循环中检索数据
DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);

END LOOP;
END;

修改游标数据

很多时候,从游标检索出来的数据要进行一些修改,比如更新游标数据或对游标数据进行删除。Oracle提供了方便的语法来处理游标数据修改的操作:在游标的声明部分添加FOR UPDATE,然后在UPDATE或DELETE语句中添加WHERE CURRENT OF。

FOR UPDATE

FOR UPDATE会对用SELECT语句提取出来的结果进行锁定,相当于给结果集的行加了一把互斥锁,实行行级锁定。这样其他的用户会话就不能对当前游标行进行修改或删除,直到整个事务被提交为止。
如:

DECLARE
dept_row dept%ROWTYPE; --定义游标结果记录变量
CURSOR dept_cursor IS SELECT * FROM dept FOR UPDATE deptno,dname; --定义游标变量
BEGIN
OPEN dept_cursor;
--打开游标
FETCH dept_cursor INTO dept_row; --提取游标数据
WHILE dept_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE('部门名称:'||dept_row.dname);
FETCH dept_cursor INTO dept_row; --提取游标数据
END LOOP;
CLOSE dept_cursor; --关闭游标
END;

WHERE CURRENT OF

在使用了FOR UPDATE锁定了表中的行后,可以在UPDATE或DELETE语句中使用WHERE CURRENT OF来得到当前游标所检索出来的行。
使用WHERE CURRENT OF检索的游标一定要有FOR UPDATE,并且游标要被打开且至少返回一行,否则Oracle会触发错误。
用法如:

DECLARE
CURSOR emp_cursor (p_deptno IN NUMBER)
IS
SELECT *
FROM emp
WHERE deptno = p_deptno
FOR UPDATE;
--使用FOR UPDATE子句添加互斥锁
BEGIN
FOR emp_row IN emp_cursor (20) --使用游标FOR循环检索游标
LOOP
UPDATE emp
SET comm = comm * 1.12
WHERE CURRENT OF emp_cursor;
--使用WHERE CURRENT OF更新游标数据
END LOOP;
COMMIT; --提交更改
END;
DECLARE
CURSOR emp_cursor (p_empno IN NUMBER)
IS
SELECT *
FROM emp
WHERE empno = p_empno
FOR UPDATE;
--使用FOR UPDATE子句添加互斥锁
BEGIN
FOR emp_row IN emp_cursor (7369) --使用游标FOR循环检索游标
LOOP
DELETE FROM emp
WHERE CURRENT OF emp_cursor;
--使用WHERE CURRENT OF删除游标数据
END LOOP;
END;