游标(cursor)是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果。每个游标区都有一个名字。用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理。
游标,从declare、open、fetch、close是一个完整过程。
以下SQL语句均在ORACLE中的scott用户下执行并通过测试。
一、定义游标的几种方式。
1.指向固定结果集的游标
declare
cursor c_emp is select * from emp;
begin
open c_emp;
--操作语句
close c_emp;
end;
/
2.定义用变量控制结果集的游标。
declare
v_sal number(7,2);
cursor c_emp is select * from emp where sal>v_sal;
begin
v_sal:= 3000;
open c_emp;
--操作语句
close c_emp;
end;
/
3.第三种游标的定义方式,带参数的游标,用的最多,与2有异曲同工之妙。
--指定参数类型时如果是number或varchar2的话不需要定义长度,否则编译不会通过。
declare
cursor c_emp(v_sal number) is select * from emp where sal>v_sal;
begin
open c_emp(3000);
--操作语句
close c_emp;
end;
/
二、游标的使用
声明游标之后,通过打开游标就可以取结果集,可以定义一个变量用于保存游标取出的单个记录或数据。
--取单个字段情况:
set serveroutput on;
declare
v_name emp.ename%type;--定义一个与emp.name相同类型的变量。
cursor c_name is select ename from emp;
begin
open c_name;
fetch c_name into v_name;
dbms_output.put_line(v_name);
--输出员工姓名。
close c_name;
end;
/
--取整个记录情况:
set serveroutput on;
declare
v_emp emp%rowtype;--定义一个与emp相同的记录类型的变量。
cursor c_emp is select * from emp;
begin
open c_emp;
fetch c_emp into v_emp;
dbms_output.put_line(v_emp.empno||v_emp.ename||v_emp.sal);
-- 输出员工编号,姓名和工资。
close c_emp;
end;
/
注:也可以在取整个记录的游标中定义一个你要取的字段的相同类型的变量比如
v_name emp.ename%type
然后令v_name:=v_emp.ename,也达到了取单个字段的目的(当然其他数据就浪费了)。
如果要取多个字段(empno,ename),可以定义一个对象类型,包含要取的字段的变量。如:
type emp_record_type is record(
emp_no emp.empno%type,
e_name emp.ename%type);
emp_rec emp_record_type;
取游标:
fetch c_emp into emp_rec.emp_no,emp_rec.e_name;
不能采用如下方式取单个字段:
fetch c_emp into v_name;--‘列表中值数量出现错误’
fetch c_emp.ename into v_name;--‘子程序或游标 'C_EMP' 引用超出范围’
三、如何用游标遍历整个结果集
在这之前先讲一下游标的四个属性: %found,%notfound,%isopen,%rowcount。
%found:若fetch语句返回了一行数据,则%found返回true。
%notfound:若fetch语句未找到数据,则%notfound返回true。
%isopen,判断游标是否打开。
%rowcount:当前游标的指针位移量,到目前位置游标所检索的记录的行数。
遍历的过程其实类似于循环语句,所以遍历也有for,while,loop等几种方式:
--loop方式遍历游标
declare
v_name varchar2(10);
cursor c_name is select ename from emp;
begin
Open c_name;
Loop
Fetch c_name into v_name;
exit when c_name%notfound;--未找到数据时退出(即到达记录末尾)。
dbms_output.put_line(v_name);
End Loop;
Close c_name;
end;
/
--while循环遍历
declare
v_name varchar2(10);
cursor c_name is select ename from emp;
begin
Open c_name;
Fetch c_name into v_name;
While c_name%Found--能找到数据则执行循环内语句。
Loop
dbms_output.put_line(v_name);
Fetch c_name into v_name;
End Loop;
Close c_name;
end;
/
--for循环遍历,最简单,用的最多,不需要声明v_student,Open和Close游标和fetch操作(不用打开游标和关闭游标,实现遍历游标最高效方式)。具体性能比较请参看我的博客。http://blog.sina.com.cn/s/blog_62defbef0101ogxr.html
declare
cursor c_name is select ename from emp;
begin
for cur in c_name--cur是固定自带的。
loop
dbms_output.put_line(cur.ename);
end loop;
end;
/
备注:以上讲的均是静态游标,动态游标请关注后续博文!