在前面的一篇文章中, 我提到了游标的生命周期,其中简单的描叙了share pool中父游标和子游标,以及缓存在 UGA 的 session cursor, 在此章中,主要阐述一下与PL/SQL相关的三种游标类型
(1)implicit cursor(隐式游标)
(2)explicit cursor(显示游标)
(3)ref cursor (外部游标)
Implicit cursor :由PL/SQL 自动管理,无需人为用代码控制游标,可以通过游标的属性来追踪游标的状态信息 , 在PL/SQL运行期间也无需使用open , pare, bind, execute, fetch and close等游标操作。隐式游标的属性值决定于最近执行的SQL,当隐式游标没有打开时,隐式游标的属性值为 空, 在DML语句执行后,隐式游标的属性将会获取值。
以下对隐式游标的属性作一个详细的总结:
SQL%FOUND属性: 一条DML语句被执行后成功后受其影响而改变的记录数是否大于等于1 ? 在一条SQL语句被执行前,SQL%FOUND的值是null。当INSERT,UPDATE,DELETE语句被执行并且其成功改变了一条或者一条以上记录的时候,或者SELECT INTO语句成功返回一条或这一条以上记录的时候,SQL%FOUND的值是true,否则SQL%FOUND的值是false。
对于SELECT INTO语句,其对应的属性值有:NO_DATA_FOUND与TOO_MANY_ROWS
SQL%NOTFOUND属性: 一条DML语句被执行成功后受其影响而改变的记录数是否为0?
在一条SQL语句被执行前,SQL%NOTFOUND的值是null。SQL%NOTFOUND逻辑上的含义和SQL%FOUND相反。当INSERT,UPDATE,DELETE语句被执行并且这些DML语句没有改变任何一条记录的时候,又或者SELECT INTO语句没有返回记录的时候,SQL%NOTFOUND的值是true,否则SQL%NOTFOUND的值是false。SQL%NOTFOUND和SELECT INTO语句连用是没有意义的:
1. 当普通的SELECT INTO语句没有返回记录的时候,马上会触发NO_DATA_FOUND
2. 当SELECT INTO语句中包含聚合函数(如max,min等)的时候,SELECT INTO语句的返回值要么有值,要么是NULL 这种情况下SQL%NOTFOUND永远是false。
SQL%ISOPEN属性: 对于隐式cursor而言,SQL%ISOPEN永远是FALSE因为oracle这里一旦执行完隐式cursor所对应的sql语句后就会自动关闭隐式cursor,所以对于隐式cursor而言,SQL%ISOPEN永远是false
SQL%ROWCOUNT属性: 一条DML语句被执行后成功后受其影响而改变的记录数是多少?SQL%ROWCOUNT表示当INSERT,UPDATE,DELETE语句被执行后受上述DML语句影响而改变的记录数,也表示SELECT INTO语句成功返回的记录数,当INSERT,UPDATE,DELETE语句被执行后没有影响任何记录,又或者SELECT INTO语句没有返回记录的时候,SQL%ROWCOUNT的值是0
注:
(1)当SELECT INTO语句返回超过一条以上记录的时候,PL/SQL这里会报错TOO_MANY_ROWS,
注意在这种情况下SQL%ROWCOUNT的返回值是1,而不是SELECT INTO语句所在的SQL实际查询到的记录数!
(2) SQL%ROWCOUNT的值仅仅代表最近一次执行的SQL,如果你在代码里需要用到某条SQL的SQL%ROWCOUNT,那就把SQL%ROWCOUNT的结果保存在一个变量里就可以了。
SQL%ROWCOUNT仅仅代表最近一次执行的SQL,它的值和transaction无关。
Explicit cursor: 一个显式游标的需要指定SQL语句, 其内套的SQL语句一旦定义, 不能改变,它不是一个变量,既不能被子程序调用, 也不能作为函数的返回值,可以使用 open, fetch, close 控制显示游标 , 但是禁止在指定的SQL 语句中 使用 for update, for update nowait 其显式游标的属性值如下:
CURSORNAME%FOUND属性: 指定的显式cursor里至少有一条记录被fetch了吗?
当一个显式cursor被open了以后,如果还一次都没有被fetch,那么CURSORNAME%FOUND的值是null 。 当这个显式cursor被fetch了后,CURSORNAME%FOUND的值为true,直到全部fetch完毕。当这个显式cursor已经被全部fetch完毕,如果你再次执行一次fetch,oracle这里并不会报错,只是此时CURSORNAME%FOUND的值为false。如果一个显式cursor还没有被open,这时候你试图使用CURSORNAME%FOUND属性,oracle这里会报错INVALID_CURSOR
CURSORNAME%ISOPEN属性: 指定的显式cursor被open了吗?这个属性通常被用于标准的exception处理流程中。用于close那些由于发生了exception而导致有显式cursor没有被正常关闭的情形
CURSORNAME%NOTFOUND属性: 指定的显式cursor fetch完毕了吗?CURSORNAME%NOTFOUND在逻辑上和CURSORNAME%FOUND相反 当一个显式cursor被open了以后,如果还一次都没有被fetch,那么CURSORNAME%NOTFOUND的值是null
当这个显式cursor被fetch了后,CURSORNAME%NOTFOUND的值为false,直到全部fetch完毕,当这个显式cursor已经被全部fetch完毕,如果你再次执行一次fetch,oracle这里并不会报错,只是此时CURSORNAME%NOTFOUND的值为true。如果一个显式cursor还没有被open,这时候你试图使用CURSORNAME%NOTFOUND属性,oracle这里会报错INVALID_CURSOR
CURSORNAME%ROWCOUNT属性: 指定的显式cursor迄今为止一共fetch了多少行记录?
当一个显式cursor被open了以后,如果还一次都没有被fetch,那么CURSORNAME%ROWCOUNT的值是0;当一个显式cursor被open了以后,如果还被fetch后返回的结果集是空的,那么CURSORNAME%ROWCOUNT的值也是0;
只要这个显式cursor被fetch过一次且返回的结果集不是空的,那么CURSORNAME%ROWCOUNT的值就不是0了,随着你的每一次fetch,CURSORNAME%ROWCOUNT的值会递增,它的值就表示指定的显式cursor迄今为止一共fetch了多少行记录,如果一个显式cursor还没有被open,这时候你试图使用CURSORNAME%ROWCOUNT属性,oracle这里会报错INVALID_CURSOR
注:
注意:
1、如果一个指定的显式cursor还没有被open,在这种情况下如果你使用了
CURSORNAME%FOUND,CURSORNAME%NOTFOUND、CURSORNAME%ROWCOUNT,oracle这里马上会报错INVALID_CURSOR
2、如果一个指定的显式cursor在首次fetch后返回的结果集是空的,那么在这种情况下
CURSORNAME%FOUND的值是false
CURSORNAME%NOTFOUND的值是true
CURSORNAME%ROWCOUNT的值是0
ref cursor:是一个多行查询的结果集,外部游标的集合一般是固定的, 它来自于特定的查询, 它是PL/SQL 的数据类型, 外部游标可以被定义为一个变量, 可以作为一个子程序的传入参数, 或者是一个函数的返回值, 外部游标也具有explicit cursor 的四个属性,
在使用外部游标时 需要注意以下几点:
(1) 当你想把一个ref cursor当做是一个存储过程的输入参数的时候,你必须指定IN或者IN OUT;并且如果你在存储过程里不仅仅是fetch,同时还open for了这个ref cursor的话,那么这里 输入参数ref cursor的类型必须定义为IN OUT.(同理,如果你在存储过程里不仅仅是fetch,同时还close了这个ref cursor的话,那么这里输入参数ref cursor的类型必须定义为IN OUT!)
(2) 只要open-for所对应的sql语句不同,你就可以无数次的open同一个ref cursor,而不必先把上一个用到的ref cursor先close再open。只是这里后来open的ref cursor会覆盖掉前一次open的ref cursor;但这里注意如果open-for所对应的sql相同,那你就只能open一次。也就是说如果你想连续两次open一个sql相同的ref cursor,oracle这里不会允许你这样做,并且会报错CURSOR_ALREADY_OPEN
(3) 不能直接在一个package的定义部分定义一个ref cursor类型的cursor变量!
一个ref cursor类型的cursor变量只能够在存储过程中定义或者作为存储过程的输入/输入输出参数。
(4) ref cursor支持单条fetch和批量fetch,
eg: FETCH emp_cv INTO emp_rec;
FETCH emp_cv BULK COLLECT INTO names, sals;
(5) ref cursor和显式cursor是可以嵌套.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8117479/viewspace-709424/,如需转载,请注明出处,否则将追究法律责任。