使用select语句可以返回一个结果集,而如果需要对结果集中单独的行进行操作,则需要使用游标。
优点:
在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标总是与一条SQL 查询语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理时,必须声明一个指向该结果集的游标。
我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。由此可见,游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且,正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。
游标的作用:
①指定结果集中特定行的位置。
②基于当前的结果集位置检索一行或连续的几行。
③在结果集的当前位置修改行中的数据。
④对其他用户所做的数据更改定义不同的敏感性级别。
⑤可以以编程的方式访问数据库。
缺点:
游标速度较慢。在创建游标时,最需要考虑的事情是,“是否有办法避免使用游标?”
因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;
如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。
一、声明游标
声明游标:划分存储区域,注意此时并没有执行Select 语句。
CURSOR 游标名( 参数 列表) [返回值类型] IS Select 语句
注意:有标的声明与使用等都需要在PL/SQL块中进行,其中声明游标需要在DECLARE子句中进行。
二、打开游标
打开游标:执行Select 语句,获得结果集存储到游标中,此时游标指向结果集头, 而不是第一条记录。
open 游标名( 参数列表);
三、检索游标
1.获取记录
获取记录:移动游标取一条记录
Fetch 游标名InTo 临时记录或属性类型变量;
2.遍历循环游标
1. loop循环游标
。。。
Loop
Fatch 游标名InTo 临时记录或属性类型变量;
Exit When 游标名%NotFound;
End Loop;
。。。
2. for循环游标
循环游标隐式打开游标,自动滚动获取一条记录,并自动创建临时记录类型变量存储记录。处理完后自动关闭游标。
注意:使用for循环时,不能对游标进行OPEN,FETCH和CLOSE操作。如果游标有输入参数,则只能使用该参数的默认值。
For 变量名 In 游标名
Loop
数据处理语句;
End Loop;
四、关闭游标
关闭游标:将游标放入缓冲池中,没有完全释放资源。可重新打开。
Close 游标名;
五、游标实例
- 实例1
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
--可以使用下面的定义方法,代替上面两个变量
--one_emp emp_cursor%rowtype;
begin
open emp_cursor(&dnum);
loop
fetch emp_cursor into v_ename,v_sal;
--判断工资低于2000,增加工资
--if(v_sal<2000)
--then update emp set sal=sal*(1.1) where ename=v_ename;
--end if;
exit when emp_cursor%NOTFOUND;
dbms_output.put_line('当前检索的是第'||emp_cursor%rowcount||'行:'||v_ename||','||v_sal);
end loop;
close emp_cursor;
end;
cursor emp_cursor(dept_num number:=20)
is
select ename,sal from emp where deptno=dept_num;
- 实例2
declare
--定义游标sp_emp_cursor
type sp_emp_cursor is ref cursor;
--定义一个游标变量
test_cursor sp_emp_cursor;
--定义变量
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
--执行
--把test_cursor和一个select结合
open test_cursor for select ename,sal from emp where deptno=&no;
--循环取出
loop
fetch test_cursor into v_ename,v_sal;
--判断是否test_cursor为空
exit when test_cursor%notfound;
dbms_output.put_line('名字:'||v_ename||' 工资:'||v_sal);
end loop;
end;