Oracle中的游标有两种:显式游标、隐式游标。显示游标是用cursor...is命令定义的游标,它可以对查询语句(select)返回的多条记录进行处理,而隐式游标是在执行插入 (insert)、删除(delete)、修改(update)和返回单条记录的查询(select)语句时由PL /SQL 自动定义的。

显式游标

当声明了显式游标后,可以通过以下三条命令控制显式游标的操作:打开游标、推进游标、关闭游标。

声明显式游标

Ø  无参游标

cursor c_auths is select * from auths

Ø  有参游标

cursor c_auths(p_code auths.author_code%type) is select * from auths where author_code=p_code

Ø  绑定变量参数的游标

v_code auths.author_code%type;

cursor c_auths is  select * from auths where author_code=v_code;

打开显式游标

打开一个已打开的游标也是合法的。当第二次打开游标时,PL /SQL 先自动关闭游标,然后再打开。一次打开多个游标也是PL /SQL 所允许的。 打开游标前为绑定变量赋值

v_code:='A00001' ;

open c_auths;

open c_auths('A00001' );   -- 打开游标时将参数传入

推进显式游标

当打开显式游标后,就可以使用FETCH语句来推进游标,返回查询结果集中的一行。每执行完一条FETCH语句后,显式游标会自动指向查询结果集的下一行。

关闭显式游标

当整个结果集都检索完以后,应当关闭游标。关闭游标用来通知PL /SQL 游标操作已经结束,并且释放游标所占用的资源(结果集所使用的资源空间)。

隐式游标

在PL/SQL中为所有的SQL数据操纵语句(包括返回一行的select)隐式声明游标 称为隐式游标。主要原因是用户不能直接命名和控制此类游标。当用户在PL/SQL 中使用数据操纵语句(DML)和select into时,oracle预先定义一个名称为SQL的隐式游标,通过检查隐式游标的属性获取与最近执行的SQL语句相关信息。

  在PL/SQL中向标准的select语句增加单独的into子句,就可以将从表或视图中查询记录赋予变量或行变量。需要注意的是select ..into 语句结果必须有且只能有一行。 如果查询没有返回行,PL/SQL将抛出no_data_found异常。如果查询返回多行,则抛出 too_many_rows 异常。如果抛出异常,则停止执行,控制权转移到异常处理部分(没有异常处理,则程序中断)。在引发异常时,将不使用属性%found,%notfound,%rowcount来查明DML语句是否 已影响了行数。

begin

update auths set entry_date_time=sysdate where author_code='A00017' ;

-- 如果update语句中修改的行不存在(SQL %notfound返回值为true ),则向auths表中插入一行。

if  sql %nofound then

insert into auths values('A000017' , 'qiuys' , 1 , '30-apr-40' , 88.5 ,sysdate);

end if ;

end;

--如果update语句中修改的行不存在(sql %rowcount=0)

declare

v_birthdate date;

begin

select birthdate into v_birthdate from auths where name='qiuys' ;

-- 如果查询到一条记录,则删除该记录。

if  sql %found then

delete from auths where name='qiuys' ;

end if ;

exception

when no_data_found then

dbms_output.put_line('该记录不存在' );

when too_many_rows then

dbms_output_line('存在同名的作家' );

end;

游标属性

Ø  %found 只有DML语句影响一行或多行时,%found属性才返回true

Ø  %notfound正好跟%found属性相反。如果DML语句没有影响任何行数 ,则%notfound属性返回true.

Ø  %rowcount返回DML语句影响的行数。如果DML语句没有影响任何行数 ,则%rowcount属性将返回0。

Ø  %isopen 判断SQL游标是否已经打开。在执行SQL语句之后,oracle自动关闭SQL 游标,所以隐式游标的%isopen属性始终为false.

游标循环

FETCH循环 

delcare

-- 声明一个变量,这个变量用来接收游标返回的结果集。

v_salary auths.salary%type;

v_code auths.author_code%type;

/*声明游标,该游标的查询结果集是作家代码为"A00001"到"A00006"的工资值。*/

cursor c_salary is select salary,author_code from auths where author_code<='A00006' ;

begin

-- 打开游标,并初始化结果集

open c_salary;

loop

-- 推进游标,将游标的查询结果集中的一行存到变量v_salary中。

fetch c_salary into v_salary,v_code;

-- 当结果集中没有行时退出循环。

exit when c_salary%notfound;

-- 如果查询到的作家工资小于或等于200 ,则增加该作家的工资值。

if  v_salary<= 200  then

update auths set salary=salary+50  where author_code=v_code;

end if ;

end loop;

-- 关闭游标,释放游标占用资源。

close c_salary;

-- 提交所做的修改。

commit;

end;

FOR循环

delcare

cursor c_salary is

select salary form auths where author_code<='A00006' ;

begin

-- 开始游标FOR循环,隐含地打开c_salary游标。

for  v_salary in c_salary loop

-- 一个隐含的fetch语句在这里被执行。

 if  v_salary.salary<= 200  then

update auths set salary=salary+50  where salary=v_salary.salary;

end if ;

--在循环继续前,一个隐含的c_auths%notfound被检测。

 end loop;

-- 现在循环已经结束,c_auths游标的一个隐含的close操作被执行。

commit;

end;

使用current of cursor子句作为条件

declare

cursor cur_emp is

elect empno , ename , job from emp where empno = 7369  for update of ename ;

begin

for return_cur in cur_emp

loop

update emp set ename = 'LHG' where current of cur_emp ;

end loop ;

end ;

其中的for update of ename 意思是给表中的行加锁,经过测试,后面的ename可以写成该表中的任何字段,因为oracle中锁的最低级别是行锁,不存在给字段加锁。

下面是行锁的作用:

1.行锁开始于一个CURSOR的OPEN,结束于一个提交COMMIT或ROLLBACK,而并不是结束于一个CURSOR的结束(CLOSE)。

2.当在一个CURSOR中对某个表的行加锁,那么如果在这个SESSION中用另一个CURSOR操作该行记录时候会等待第一个cursor的完成提交,直到第一个cursor提交完成之后,第二个cursor中对改行的操作才会开始执行。

3.当第一个cursor中的由于操作错误而不能提交时候,第二个cursor将会一直等待下去,这样就形成了死锁。预防这种情况发生的方法是在for update of ename 之后指定NOWAIT选项,这样的话,当第二个cursor不会一直等待下去,而是出现 ORA-00054 [resource busy and acquire with NOWAIT specified] 的讯息。

4.既然for update of后面的字段是随便那个字段都可以,那么可不可以不写呢?如果你没必要指定NOWAIT选项,那么后面的字段就可以不写;如果你必须指定NOWAIT选项,则必须指定至少一个字段。

5.还有一种方法是用ROWID 替代WHERE CURRENT OF YOUR_CURSOR_NAME 语句。

如下代码:

declare
      cursor cur_emp is select a . deptno ,a . dname , a . rowid , b . rowid rowid_1

from dept a , emp b where empno = 7369 and a . deptno = b . deptno for update nowait ;

v_deptno dept . deptno % type ;
     v_dname dept . dname % type ;
     v_rowid rowid ;
     v_rowid_1 rowid ;
begin
     open cur_emp ;
     loop
     fetch cur_emp into v_deptno , v_dname , v_rowid , v_rowid_1 ;
     exit when cur_emp % notfound ;
        update dept set dname = 'abc' where rowid = v_rowid ;
        update emp set ename = 'frank'  where rowid = v_rowid_1 ;
     end loop ;
     close cur_emp ;
     commit ;
exception
     when others then
        rollback ;
        raise ;
end ;

由此,推荐的for update的习惯是:

Ø  NOWAIT 定然跟FOR UPDATE 之后。

Ø  直接用ROWID 替代WHERE CURRENT OF YOUR_CURSOR_NAME 语句,尤其在相对繁习的程序里头。

Ø  COMMIT 必需存在程序结尾。以防死锁成形。

Ø  EXCEPTION 里的ROLLBACK 是最基本的需要。

游标变量

到目前为止前面所有显式游标的例子都是静态游标-即游标与一个SQL 语句关联,并且该SQL 语句在编译时已经确定。而游标变量是一个引用类型(REF)的变量。

游标变量的声明

-- 使用%rowtype定义一个游标变量类型。

type t_authsref is ref cursor return auths%rowtype;

v_authcv t_authsref;

PL /SQL2.8以上版本中,可以使用一个没有指定结果集类型的游标变量来指定多个不同类型的查询。

type t_authsref is ref cursor;

v_ authscv  t_authsref;--声明一个该类型的变量。

打开游标变量  

为了将一个游标变更与一个具体的select语句联系起来,open的语法中增加了一个select语句。

open v_authscv for  select * from auths;

关闭游标操作

关闭游标操作用来释放查询所占用的资源。但没有释放游标变量占用的存储空间。当变量超出作用域时,它所占用的空间才被释放掉。 下面的块中定义了一个没有指定结果集的游标变量,这样我们就可以使用这个游标变量指向不同的查询,并能够返回不同的记录类型:

set serveroutput on size  100000  --设置存储缓冲区大小。

declare

/*定义游标变更类型t_curref,该游标变量类型没有指定结果集类型,所以该游标变量类型的变量可以返回不同的PL /SQL 记录类型。*/

type t_curref is ref cursor;

-- 声明一个游标变量类型的变量

c_cursorref t_curref;

-- 定义PL /SQL 记录类型 t_authorrec,该类型的变量用来接收游标变量的返回值。

type t_authorrec is record(

authorcode auths.author_code%type,

name auths.name%type);

-- 定义PL /SQL 记录类型 t_articlerec,该类型的变量也用来接收游标变量的返回值。

type t_articlerec is record(

authorcode article.author_code%type,

title artitle.title%type);

-- 声明两个记录类型变量。

v_author t_authorrec;

v_article t_articlerec;

begin

-- 打开游标变量c_cursorref,返回t_authorrec类型的记录。

open c_cursorref for

select author_code,name from auths where author_code in('A00001' , 'A00002' , 'A00003' , 'A00004' , 'A00005' );

-- 推进游标变量

fetch c_cursorref into v_author;

-- 游标变量的推进循环。

while  c_cursorref%found loop

-- 将作家代码和相应的作家名字输出到屏幕上。

dbms_output.put(v_author.authorcode||':' ||v_author.name|| ' ' );

fetch c_cursorref into v_author;

end loop;

dbms_output.new_line;-- 向屏幕上输出一个回车行。

--关闭游标变量,仅仅将游标变量指定的资源释放掉,游标变量本身的存储空间没有释放掉。

close c_cursorref;

-- 再次打开游标变量,返回t_articlerec类型的记录。

open c_cursorref for

select author_code,title from article

where author_code in('A00001' , 'A00002' , 'A00003' , 'A00004' , 'A00005' );

fetch c_cursorref into v_article;

while  c_cursorref%found loop

...

end loop;

close c_cursorref;

end;

注意,在上例中,第一次关闭游标变量是可省略的,因为在第二次打开游标变量时,就将第一次的查询丢失掉了。而且游标变量也有游标属性,通常在推进游标变量时使用这些游标属性,例如上例使用了%found属性。

(转自 http://blog.csdn.net/bupt_zoucq/article/details/6771585)

Oracle中的游标(转)的更多相关文章

  1. oracle 中的游标

    oracle 中的游标 通俗易懂的sql代码直接上! --简单的游标使用滴呀 --使用FOR OBJ IN OBJS LOOP ......END LOOP; DECLARE CURSOR C_JOB ...

  2. Oracle中使用游标转换数据表中指定字段内容格式(拼音转数字)

    应用场景:将数据表TB_USER中字段NNDP的内容中为[sannanyinv]转换为[3男1女] 主要脚本:一个游标脚本+分割字符串函数+拼音转数字脚本 操作步骤如下: 1.创建类型 create ...

  3. Oracle中使用游标获取指定数据表的所有字段名对应的字符串

    操作步骤:打开PLSQL Developer后,直接执行下面的语句就可以出来 --Oracle中使用游标获取指定数据表的所有字段名对应的字符串 declare mytablename VARCHAR( ...

  4. java实现调用ORACLE中的游标和包

    今天把oracle中的包和游标学习了下,不废话,网上的的有些代码是错误的,抄来抄去,就自己实践了下,做个记录.直接上图,上代码 通过plsql创建自己的的包,包分为包头和包体. 1.包头如下: CRE ...

  5. Oracle中的游标

    Oracle游标 概念:内存中的一块区域,存放select结果 游标用来处理从数据库中检索的多行记录(使用SELECT语句).利用游标,程序可以逐个地处理和遍历一次检索返回的整个记录集.一.显示游标( ...

  6. Oracle 中的游标(用Javase中Iterator 类比之)

    当使用 pl/sql 查询 Oracle 数据库时,有时我们想输出多条记录的数据.:select * from scott.emp; 这时,我们一定会想利用循环来输出.但是,在pl/sql 中是没有数 ...

  7. Oracle中的游标的原理和使用详解

    游标的简介 逐行处理查询结果,以编程的方式访问数据. 游标的类型: 1,隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标,名字固定叫sql. 2,显式游标:显式游标用于处理 ...

  8. 【转】oracle中的游标的原理和使用详解

    游标 游标的简介: 逐行处理查询结果,以编程的方式访问数据 游标的类型: 1,隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标,名字固定叫sql. 2,显式游标:显式游标用 ...

  9. ORACLE中的游标Cursor总结

    游标(Cursor):用来查询数据库,获取记录集合(结果集)的指针,可以让开发者一次访问一行结果集,在每条结果集上作操作. 游标可分为: 1.       静态游标:分为显式(explicit)游标和 ...

随机推荐

  1. IOS系统不兼容position: fixed;属性的解决方案

    position: fixed;属性在IOS系统手机上会有很明显的抖动,解决方式: 只需要在中间部分外层div添加css样式position:fixed;top:50px; bottom:50px;o ...

  2. python缩进报错

    1.这个错误应该已经好久了:也应该熟悉了才对 IndentationError: unexpected indent python 缩进错误:意外缩进Python 但今天的问题有点特殊,我想在程序中间 ...

  3. Appium_Java运行测试脚本时问题汇总

    问题一.java.lang.NoClassDefFoundError: org/openqa/selenium/remote/SessionNotFoundExceptionCaused by: ja ...

  4. 【前端切图】用css画一个卡通形象-小猪佩奇

    最近在腾讯云技术社区遇到了一位奇才,用css画出了一个社会人小猪佩奇,不得不服.研究了一下他的文章https://segmentfault.com/a/1190000014909658,感觉甚是有趣, ...

  5. spring使用context:property-placeholder载不进属性问题 wangbiglei 发表于1年前 原 spring使用context:property-placeholder载不进属性问题

    https://my.oschina.net/wangbiglei/blog/489583 http://www.cnblogs.com/leftthen/p/5615066.html

  6. Android多线程研究(6)——多线程之间数据隔离

    在上一篇<Android多线程研究(5)--线程之间共享数据>中对线程之间的数据共享进行了学习和研究,这一篇我们来看看怎样解决多个线程之间的数据隔离问题,什么是数据隔离呢?比方说我们如今开 ...

  7. 好记性不如烂笔头——datagridview相关

    DataGridViewTextBoxColumn dgv_IDY = new DataGridViewTextBoxColumn(); dgv_IDY.Visible = false; dgv_ID ...

  8. 【Codeforces Round #442 (Div. 2) C】Slava and tanks

    [链接] 我是链接,点我呀:) [题意] 有n个位置,每个位置都可能有不定数量的tank; 你每次可以选择一个位置投掷炸弹. 并且,这个位置上的所有tank都会受到你的攻击. 并且失去一点体力. 然后 ...

  9. decode与case when

    语法 decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) select * from reglike; ,),'aaa','yes','no') decode from ...

  10. [TypeScript] Using Interfaces to Describe Types in TypeScript

    It’s easy to pass the wrong value to a function. Typescript interfaces are great because they catch ...