1、游标
A.游标概论
游标是一个私有的SQL工作区域,Oracle数据库中有两种游标,分别是隐式游标和显式游标, 隐式游标不易被用户和程序员察觉和意识到,实际上Oracle服务器使用隐式游标来解析和执行提交的SQL 语句; 而显式游标是程序员在程序中显式声明的;通常游标均指显式游标。
B.隐式游标
SQL%ROWCOUNT 受最近的SQL语句影响的行数SQL%FOUND 最近的SQL语句是否影响了一行以上的 数据SQL%NOTFOUND 最近的SQL语句是否未影响任何数据SQL%ISOPEN 对于隐式游标而言永远为FALSE
VARIABLE rows_deleted VARCHAR2(30)DECLAREv_employee_id employees.employee_id%TYPE := 176;BEGINDELETE FROM employeesWHERE employee_id = v_employee_id;:rows_deleted := (SQL%ROWCOUNT ||' row deleted.');END;/PRINT rows_deleted
C.显式游标
对于返回多行结果的SQL语句的返回结果,可使用显式游标独立的处理器中每一行的数据。
显式游标的相关函数可以做到:
1、一行一行的处理返回的数据。
2、保持当前处理行的一个跟踪,像一个指针一样指示当前的处理的记录。
3、允许程序员在PLSQL块中人为的控制游标的开启、关闭、上下移动;
D.在程序中对显式游标控制的一般过程

DECLAREv_empno employees.employee_id%TYPE;v_ename employees.last_name%TYPE;CURSOR emp_cursor ISSELECT employee_id, last_nameFROM employees;BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_empno, v_ename;EXIT WHEN emp_cursor%ROWCOUNT > 10 ORemp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_empno)||' '|| v_ename);END LOOP;CLOSE emp_cursor;END ;
For循环进行游标的遍历,For循环省去了游标的 声明、打开、提取、测试、关闭等语句
FOR record_name IN cursor_name LOOPstatement1;statement2;. . .END LOOP;
BEGINFOR emp_record IN (SELECT last_name, department_idFROM employees) LOOP-- implicit open and implicit fetch occurIF emp_record.department_id = 80 THEN...END LOOP; -- implicit close occursEND;
DECLARECURSOR emp_cursor ISSELECT last_name, department_idFROM employees;BEGINFOR emp_record IN emp_cursor LOOP-- implicit open and implicit fetch occurIF emp_record.department_id = 80 THEN...END LOOP; -- implicit close occursEND;/
E.游标带参数
CURSOR cursor_name[(parameter_name datatype, ...)]ISselect_statement;
DECLARECURSOR emp_cursor(p_deptno NUMBER, p_job VARCHAR2) ISSELECT employee_id, last_nameFROM employeesWHERE department_id = p_deptnoAND job_id = p_job;BEGINOPEN emp_cursor (80, 'SA_REP');. . .CLOSE emp_cursor;OPEN emp_cursor (60, 'IT_PROG');. . .END;
F.FOR UPDATE NOWAIT语句
有的时候打开一个游标是为了更新或者删除一些记录,这种情况下希望在打开游标的时候即锁定相关记录,应该使用for update nowait语句,倘若锁定失败就停止不再继续,以免出现长时间等待资源的死锁情况。
SELECT ...FROM ...FOR UPDATE [OF column_reference][NOWAIT];
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, department_nameFROM employees,departmentsWHERE employees.department_id =departments.department_idAND employees.department_id = 80FOR UPDATE OF salary NOWAIT;
G.WHERE CURRENT OF cursor
经常要逐条处理游标中的每一条记录,在循环体内做Update 或者 Delete 时需要有Where指向游标的当前记录可以使用WHERE CURRENT OF cursor
DECLARECURSOR sal_cursor ISSELECT e.department_id, employee_id, last_name, salaryFROM employees e, departments dWHERE d.department_id = e.department_idand d.department_id = 60FOR UPDATE OF salary NOWAIT;BEGINFOR emp_record IN sal_cursorLOOPIF emp_record.salary < 5000 THENUPDATE employeesSET salary = emp_record.salary * 1.10WHERE CURRENT OF sal_cursor;END IF;END LOOP;END;/
