游标是从表中提取的数据以临时表的形式存放内存中,游标中有一个数据指针,默认指向的是第一条记录。利用fetch语句移动该指针,从而对游标中的数据进行操作。
语法:
cursor 游标名 is select 语句;
--cursor是定义游标的关键词
--select是建立游标的数据表查询命令.
打开游标:
open 游标名;
打开游标相当于执行了下面两个动作:
a.将符合条件的记录送入内存
b.将指针指向第一条记录
移动指针,将数据提取出来:
fetch 游标名 into 变量名1,变量名2,.......;
fetch 游标名 into 记录型变量名;
关闭游标:
close 游标名;
游标的属性:
--使用方法:游标名%属性
cursor%isopen
--测试游标是否打开,如果没有打开游标就使用fetch语句将提示错误
cursor%found属性
--测试前一个fetch语句是否有数据,有值将返回true,否则为false
cursor%notfound属性
--%found属性的反逻辑,常被用于退出循环,判断游标是否没有数据
cursor%rowcount属性
--用于返回游标的数据行数,若返回值为0,表明游标已经打开,但没有提取出数据.
游标的简单运用:首先建立一个表employee,包含以下字段,往表里插入一些数据;
1.取表里满足条件的第一条记录:
declare
tempsal employee.salary%type;
cursor mycursor is
select * from employee where salary<tempsal;
cursorrecord mycursor%rowtype;
begin
tempsal:=2000;
open mycursor;
fetch mycursor into cursorrecord;
--dbms_output.put_line('test111');
dbms_output.put_line(cursorrecord.empid);
close mycursor;
end;
-----输出结果是:14
2.取满足条件的所有记录需要用到循环,让游标往下移动取值:
declare
tempsal employee.salary%type;
cursor mycursor is
select * from employee where salary<tempsal;
cursorrecord mycursor%rowtype;
begin
tempsal:=2000; --取工资小于2000的放在放在内存中
open mycursor;
--fetch mycursor into cursorrecord; ---注意这里没有fetch(若放在这结果没有首记录)
loop ---循环
fetch mycursor into cursorrecord;
---dbms_output.put_line('test111');
exit when mycursor%notfound; ---没有取到数据了才退出来
---dbms_output.put_line('test222');
dbms_output.put_line(cursorrecord.empid);
end loop;
close mycursor;
end;
-----执行上面结果输出是:14 15 16 17 18
-----若也加上第一个fetch,输出结果为:15 16 17 18。自己可以看程序运行轨迹。
3.取满足条件的前面几条记录,循环时用到for i in 1..n loop(n自己确定):
declare
tempsal employee.salary%type;
cursor mycursor is
select * from employee where salary<tempsal;
cursorrecord mycursor%rowtype;
begin
tempsal:=2000;
open mycursor;
for i in 1..3 loop --游标指针指向对应的数据3次(第一次是首记录)
fetch mycursor into cursorrecord;
--dbms_output.put_line('test222222222222');
exit when mycursor%notfound;
--dbms_output.put_line('test333333333333333');
dbms_output.put_line(cursorrecord.empid);
end loop;
close mycursor;
end;
-----输出的结果是:14 15 16
4.利用mycursor%rowcount确定跳出循环的时间,%rowcount的值要<=满足要求的总记录数
declare
tempsal employee.salary%type;
cursor mycursor is
select * from employee where salary<tempsal;
cursorrecord mycursor%rowtype;
begin
tempsal:=2000;
open mycursor;
loop
fetch mycursor into cursorrecord;
dbms_output.put_line('test111');
-----exit when mycursor%rowcount=4;
dbms_output.put_line(cursorrecord.empid);
dbms_output.put_line(mycursor%rowcount);
exit when mycursor%rowcount=4; --注意这里%rowcount的取值要小于等于总记录数
end loop;
close mycursor;
end;
注意exit when mycursor%rowcount=4的位置:
如果在上面,结果只显示%rowcount-1条记录,原因是只要%rowcount=?后,循环就提前跳出了,没有执行下面的输出语句。
如果在下面,先执行输出语句再判断,判断为false就跳出循环了,输出的结果数位%rowcount个。
5.带参数的游标
declare
cursor mycur(vartype number) is select * from employee where employee.salary=vartype;
begin
for emp in mycur(2000) loop
dbms_output.put_line(emp.empid||','||emp.salary);
end loop;
end;
mycur(2000)是将工资为2000的所有记录放在临时表中,emp为变量名,for emp in mycur(2000) loop是循环取临时表里的数据。
6.存储过程中使用游标
create or replace procedure emp_pro_cur
as
cursor cur is select * from employee where employee.empname like 'd%';
begin
for emp in cur loop --这里for循环,不需要使用fetch移动游标指针
dbms_output.put_line(emp.empname);
end loop;
end;
--调用存储过程
call emp_pro_cur();