一、游标和记录
此示例中的游标基于SELECT语句,该语句仅检索每个表行的两列。 如果它检索了六列或七,八,二十个呢?
DECLAREv_emp_id employees.employee_id%TYPE;v_last_name employees.last_name%TYPE;CURSOR emp_cursor ISSELECT employee_id, last_nameFROM employeesWHERE department_id = 30;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursorINTO v_emp_id, v_last_name;...
该游标检索整个EMPLOYEES行。 凌乱而啰嗦,不是吗?
DECLAREv_emp_id employees.employee_id%TYPE;v_first_name employees.first_name%TYPE;v_last_name employees.last_name%TYPE;...v_department_id employees.department_id%TYPE;CURSOR emp_cursor ISSELECT * FROM employeesWHERE department_id = 30;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursorINTO v_emp_id, v_first_name, v_last_name ...v_department_id;...
比较下面的代码片段。 你看到了什么差异?
DECLAREv_emp_id ...;v_first_name ...;...v_department_id ...:CURSOR emp_cursor ISSELECT * FROM employeesWHERE department_id =30;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursorINTO v_emp_id, v_first_name,... v_department_id;...
DECLARECURSOR emp_cursor ISSELECT * FROM employeesWHERE department_id = 30;v_emp_recordemp_cursor%ROWTYPE;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursorINTO v_emp_record;...
右侧的代码使用%ROWTYPE根据游标声明记录结构。 记录是PL / SQL中的复合数据类型。
二、PL / SQL记录的结构
记录是一种复合数据类型,由多个字段组成,每个字段都有自己的名称和数据类型。 您通过在字段名前加上记录名来引用每个字段。 %ROWTYPE用与它所基于的游标相同的字段声明一个记录。
(1)cursor_name%ROWTYPE的结构
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name, salary FROM employeesWHERE department_id = 30;v_emp_record emp_cursor%ROWTYPE;
(2)游标和%ROWTYPE
%ROWTYPE便于处理活动集的行,因为您可以简单地获取记录。
DECLARECURSOR emp_cursor ISSELECT * FROM employeesWHERE department_id = 30;
v_emp_record emp_cursor%ROWTYPE;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_emp_record;EXIT WHEN emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id|| ' - '
||v_emp_record.last_name);END LOOP;CLOSE emp_cursor;
END;
(3)游标和%ROWTYPE:另一个例子
DECLARECURSOR emp_dept_cursor ISSELECT first_name, last_name, department_nameFROM employees e, departments dWHERE e.department_id = d.department_id;
v_emp_dept_record emp_dept_cursor%ROWTYPE;
BEGINOPEN emp_dept_cursor;LOOPFETCH emp_dept_cursor INTO v_emp_dept_record;EXIT WHEN emp_dept_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_dept_record.first_name||' – '||v_emp_dept_record.last_name||' – '||v_emp_dept_record.department_name);END LOOP;CLOSE emp_dept_cursor;
END;
三、显式游标属性
与隐式游标一样,有几个属性可用于获取有关显式游标的状态信息。 当附加到游标变量名称后,这些属性返回有关游标操作语句执行的有用信息。
(1)%ISOPEN属性
只有当光标打开时才可以获取行。 在执行提取以测试游标是否处于打开状态之前,请使用%ISOPEN游标属性。 %ISOPEN返回游标状态:如果打开则为TRUE,否则返回FALSE。
例:
IF NOT emp_cursor%ISOPEN THEN
OPEN emp_cursor;
END IF;
LOOPFETCH emp_cursor...
(2)%ROWCOUNT和%NOTFOUND属性
通常在循环中使用%ROWCOUNT和%NOTFOUND属性来确定何时退出循环。
对以下内容使用%ROWCOUNT游标属性:
•处理确切的行数
•计算循环中到目前为止获取的行数和/或确定何时退出循环
对以下内容使用%NOTFOUND游标属性:
•确定查询是否找到符合条件的行
•确定何时退出循环
(3)%ROWCOUNT和%NOTFOUND的示例
此示例显示了如何在循环中使用%ROWCOUNT和%NOTFOUND属性作为退出条件。
DECLARECURSOR emp_cursor ISSELECT employee_id, last_name FROM employees;v_emp_record emp_cursor%ROWTYPE;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_emp_record;EXIT WHEN emp_cursor%ROWCOUNT > 10 OR emp_cursor%NOTFOUND;DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id |' '|| v_emp_record.last_name);END LOOP;CLOSE emp_cursor;
END;
(4)SQL语句中的显式游标属性
您不能直接在SQL语句中使用显式游标属性。 以下代码返回一个错误:
DECLARECURSOR emp_cursor ISSELECT employee_id, salary FROM employeesORDER BY SALARY DESC;v_emp_record emp_cursor%ROWTYPE;v_count NUMBER;
BEGINOPEN emp_cursor;LOOPFETCH emp_cursor INTO v_emp_record;EXIT WHEN emp_cursor%NOTFOUND;INSERT INTO top_paid_emps(employee_id, rank, salary)VALUES(v_emp_record.employee_id, emp_cursor%ROWCOUNT,v_emp_record.salary);
...