1. 分类

常见的游标可分为显示游标、隐式游标、静态游标和动态游标四大类:

1.1 显示游标

显式是相对与隐式cursor而言的,就是有一个明确的声明的cursor。显式游标的声明类似如下:

delcare 游标关键字cursor 游标名 is 数据集;

游标从declare、open、fetch、close是一个完整的生命旅程。当然了一个这样的游标是可以被多次open进行使用的,显式cursor是静态cursor,她的作用域是全局的,但也必须明白,静态cursor也只有pl/sql代码才可以使用她。下面看一个简单的静态显式cursor的示例:

 declare
cursor get_subid(pid a_test.parentid%type) is
select subid from a_test where parentid = pid;
v_subid a_test.subid%type;
begin
open get_subid(1);
loop
fetch get_subid
into v_subid;
exit when get_subid%notfound;
dbms_output.put_line(v_subid);
end loop;
close get_subid;
dbms_output.put_line('--------这是分割线----------');
open get_subid(4);
loop
fetch get_subid
into v_subid;
exit when get_subid%notfound;
dbms_output.put_line(v_subid);
end loop;
close get_subid;
end;

1.2 隐式游标

隐式cursor当然是相对于显式而言的,就是没有明确的cursor的declare。在Oracle的PL/SQL中,所有的DML操作都被Oracle内部解析为一个cursor名为SQL的隐式游标,只是对我们透明罢了。

begin
for rec in (select user, sysdate from dual) loop
dbms_output.put_line(rec.user || ':' ||
to_char(rec.sysdate, 'yyyy-mm-dd hh24:mi:ss'));
end loop;
end;

1.3 静态游标

静态游标是相对于动态游标而言的,普通显示定义的游标都是静态游标。

1.4 动态游标

动态游标是相对于静态游标而言的,要等到运行时才知道结果集查询语句是什么样的。

 declare
type atest_rec is record(
pid a_test.parentid%type,
subid a_test.subid%type); type app_ref_cur_type is ref cursor return atest_rec;
my_cur app_ref_cur_type;
my_rec atest_rec;
begin if (to_char(sysdate, 'dd') = 30) then
open my_cur for
select parentid, subid from a_test where parentid = 1;
else
open my_cur for
select parentid, subid from a_test where parentid = 2;
end if; fetch my_cur
into my_rec;
while my_cur%found loop
--当前不是30号 执行else 结果:
--2#4
--2#5
dbms_output.put_line(my_rec.pid || '#' || my_rec.subid);
fetch my_cur
into my_rec;
end loop;
close my_cur; end;

  【注】Record为记录数据类型。它类似于C语言中的结构数据类型(STRUCTURE),PL/SQL提供了将几个相关的、分离的、基本数据类型的变量组成一个整体的方法,即RECORD复合数据类型。在使用记录数据类型变量时,需要在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。

  定义记录数据类型的语法如下:

 TYPE RECORD_NAME IS RECORD(
V1 DATA_TYPE1 [NOT NULL][:=DEFAULT_VALUE],
V2 DATA_TYPE2 [NOT NULL][:=DEFAULT_VALUE],
VN DATA_TYPEN [NOT NULL][:=DEFAULT_VALUE]);

由上面的例子,可知cursor与REF cursor大致有以下几点区别:

1)PL/SQL静态游标不能返回到客户端,只有PL/SQL才能利用它。动态游标能够被返回到客户端,这就是从Oracle的存储过程返回结果集的方式。

2)PL/SQL静态游标可以是全局的,而动态游标则不是,不能在包说明或包体中的过程或函数之外定义动态游标。

3)动态游标可以从子例程传递到子例程,而普通游标则不能。如果要共享静态光标,必须在包说明或包体中把它定义为全局光标。 因为使用全局变量通常不是一种很好的编码习惯,因此可以用动态游标来共享PL/SQL中的游标,无需混合使用全局变量。

4)静态光标比动态游标标效率要高,所以在使用游标时首先考虑使用静态游标,也有人建议尽量使用隐式游标,避免编写附加的游标控制代码(声明,打开,获取,关闭),也不需要声明变量来保存从游标中获取的数据。这个就因人因事而定吧。

另外,在oracle9i以后系统定义的一个refcursor, 这是一个弱类型的游标,相当于.Net中用户var声明的变量,主要用在过程中返回结果集。

 --创建存储过程
create or replace procedure sp_get_subid(pid ina_test.parentid%type,
out_subid out SYS_REFCURSOR) as
begin
open out_subid for
SELECT * FROM a_test WHERE parentid = pid;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20101, 'Error in sp_get_subid' || SQLCODE);
end sp_get_subid; --调用存储过程
declare
v_rent_rows SYS_REFCURSOR;
v_rent_row a_test%rowType;
begin
sp_get_subid(1, v_rent_rows);
Dbms_output.put_line('parentid subid');
loop
fetch v _rows
into v _row;
exit when v _rows%NOTFOUND;
Dbms_output.put_line(v _row.parentid || ' ' || v _row.subid);
end loop;
close v_rows;
end;

2. 属性

2.1 说明

 %FOUND: bool - TRUE if >1 row returned
%NOTFOUND:bool - TRUE if 0 rows returned
%ISOPEN: bool - TRUE if cursor still open
%ROWCOUNT:int - number of rows affected by last SQL statement

【注】NO_DATA_FOUND和%NOTFOUND的用法是有区别的,小结如下:

1)SELECT . . . INTO 语句触发 NO_DATA_FOUND;

2)当一个显式游标的 where 子句未找到时触发 %NOTFOUND;

3)当UPDATE或DELETE 语句的where 子句未找到时触发 SQL%NOTFOUND;

4)在游标的提取(Fetch)循环中要用 %NOTFOUND 或%FOUND 来确定循环的退出条件,不要用NO_DATA_FOUND

2.2 示例

2.2.1 示例一:

 begin

   update A_TEST set SUBID = '' WHERE PARENTID = 4;

   --SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE,如果游标关闭,则为FALSE.

   if sql%isopen then

     dbms_output.put_line('Openging');

   else

     dbms_output.put_line('closing'); --对于隐式游标而言SQL%ISOPEN总是FALSE,这是因为隐式游标在DML语句执行时打开,结束时就立即关闭。

   end if;

   if sql%found then

     dbms_output.put_line('游标指向了有效行'); --判断游标是否指向有效行

   else

     dbms_output.put_line('Sorry');

   end if;

   if sql%notfound then

     dbms_output.put_line('Also Sorry');

   else

     dbms_output.put_line('Haha');

   end if;

   dbms_output.put_line(sql%rowcount);

 exception

   when no_data_found then

     dbms_output.put_line('Sorry No data');

   when too_many_rows then

     dbms_output.put_line('Too Many rows');

 end;

【注】SQL语言分为DDL(Data Definition Language,数据定义语言,用来维护数据对象)和DML(Data Manipulation Language,数据操作语言,用于增删改表中数据,DML是伴随TCL事务控制的)。

2.2.2 示例二:

 declare

   empNumber a_test.parentid%TYPE;

   empName   a_test.subid%TYPE;

 begin

   if sql%isopen then

     dbms_output.put_line('Cursor is opinging');

   else

     dbms_output.put_line('Cursor is Close');

   end if;

   if sql%notfound then

     dbms_output.put_line('No Value');

   else

     dbms_output.put_line(empNumber); --没有赋值,输出为空白

   end if;

   dbms_output.put_line(sql%rowcount); --没有记录,输出为空白

   dbms_output.put_line('-------------');

   select parentid, subid into empNumber, empName from a_test where parentid = 4;

   dbms_output.put_line(sql%rowcount);

   if sql%isopen then

     dbms_output.put_line('Cursor is opinging');

   else

     dbms_output.put_line('Cursor is Closing');

   end if;

   if sql%notfound then

     dbms_output.put_line('No Value');

   else

     dbms_output.put_line(empNumber);

   end if;

 exception

   when no_data_found then

     dbms_output.put_line('No Value');

   when too_many_rows then

     dbms_output.put_line('too many rows');

 end;

【注】%Type是Oracle提供的一种数据定义方法,为的是使一个新定义的变量与另一个已经定义了的变量(通常是表的某一列)的数据类型保持一致,当被参照的那个变量的数据类型发生改变时,那么这个新定义的变量的数据类型也会随之发生改变。当不能确切的知道那个变量的类型是,就采用这种方法来定义变量的数据类型。

3. 操作

3.1 For循环游标

  --声明游标:delcare 游标关键字cursor 游标名 is 数据集;

 declare

 cursorc_list is

 selectp.fid, max(t.exp) exp

 from view_pilot p

 left join IO_FMS_BILLOFHEALTH t

 ont.phr = p.fjobnumber

 group by p.fid;

 --For循环,类似.Net中的foreach方法:

 --begin

 --for 元素名 in 游标名 循环关键字loop

 --执行语句;

 --endloop;

 begin

   for c_row in c_list loop

     update alarm_pilotintelligence

        set C = GetAlarmStateByExp(c_row.exp)

      where isprimary = 0

        and pid = c_row.fid;

 end loop;

3.2 Fetch游标

 --定义游标

 declare

   cursor c_job is

     select * from a_test order by parentid;

   --定义一个游标变量

   c_row c_job%rowtype;

 begin

   --使用的时候必须要明确的打开游标

   Open c_job;

   --开始循环标记

   loop

     --提取一行数据到c_row,相当ADO.Net中的SqlDataReader.Read()方法

     fetch c_job into c_row;

     --判读是否提取到值,没取到值就退出

     --取到值c_job%notfound 是false

     --取不到值c_job%notfound 是true

     exit when c_job%notfound;

     dbms_output.put_line(c_row.parentid || '-' || c_row.subid); --用于输出,这是oracle中最基础的方法之一

     --结束循环,并关闭游标

   end loop;

   close c_job;

 end;

【注】如果一个表有较多的列,使用%ROWTYPE来定义一个表示表中一行记录的变量,比分别使用%TYPE来定义表示表中各个列的变量要简洁得多,并且不容易遗漏、出错。这样会增加程序的可维护性。当不能确切地知道被参照的那个表的结构及其数据类型时,可以采用这种方法定义变量的数据类型。

3.3 While循环游标

  上面【示例二】中的结果还可以通过While循环与Fetch相结合来实现:

 --定义游标

 declare

   cursor c_job is

     select * from a_test order by parentid;

   --定义一个游标变量

   c_row c_job%rowtype;

 begin

   --使用的时候必须要明确的打开游标

   Open c_job;

   --开始循环标记

   --提取一行数据到c_row,相当ADO.Net中的SqlDataReader.Read()方法

   fetch c_job

     into c_row;

   --while循环

   while c_job%found loop

     dbms_output.put_line(c_row.parentid || '-' || c_row.subid);

     fetch c_job

       into c_row;

     --结束循环,并关闭游标

   end loop;

   close c_job;

 end;

参考资料:

1.Oracle 游标使用全解

2.游标属性SQL%FOUND, SQL%NOTFOUND, SQL%ROWCOUNT, SQL%ISOPEN

3.ORACLE中%TYPE和%ROWTYPE的使用

4. cursor 与refcursor及sys_refcursor的区别 (转载)

【Oracle学习笔记】游标的更多相关文章

  1. (七)Oracle学习笔记—— 游标

    1.游标简介 游标用来处理从数据库中检索的多行记录(使用SELECT语句).利用游标,程序可以逐个地处理和遍历一次检索返回的整个记录集. 为了处理SQL语句,Oracle将在内存中分配一个区域,这就是 ...

  2. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  3. oracle学习笔记第一天

    oracle学习笔记第一天 --oracle学习的第一天 --一.几个基础的关键字   1.select select (挑选) 挑选出显示的--列--(可以多列,用“,”隔开,*表示所有列),为一条 ...

  4. Oracle学习笔记——点滴汇总

    Oracle学习笔记——点滴汇总 http://www.botangdb.com/ Oracle GI = Grid Infrastructure = ASM + Cluster

  5. Oracle学习笔记之四sp1,Oracle 11g的常用函数

    从Oracle学习笔记之四,SQL语言入门中摘出来的,独立成一章节 3.1 字符类函数 ASCII(c)和CHR(i)    分别用于返回一个字符的ASCII码和返回给定ASCII值所对应的字符. C ...

  6. Oracle学习笔记之四,SQL语言入门

    1. SQL语言概述 1.1 SQL语言特点 集合性,SQL可以的高层的数据结构上进行工作,工作时不是单条地处理记录,而对数据进行成组的处理. 统一性,操作任务主要包括:查询数据:插入.修改和删除数据 ...

  7. Oracle学习笔记—数据字典和常用命令(转载)

    转载自: oracle常用数据字典和SQL语句总结 Oracle常用命令大全(很有用,做笔记) 一.Oracle数据字典 数据字典是Oracle存放有关数据库信息的地方,其用途是用来描述数据的.比如一 ...

  8. oracle学习笔记(一)用户管理

    --oracle学习第一天 --连接 @后面连接数据库实例,具体连接到那个数据库 conn scott/tiger@MYORA1; --修改密码 passw; --显示用户 show user; -- ...

  9. 吴裕雄--天生自然 oracle学习笔记:oracle理论学习详解及各种简单操作例子

    1. 数据库的发展过程 层次模型 -->网状模型 -->关系模型 -->对象关系模型 2. 关于数据库的概念 DB:数据库(存储信息的仓库) DBMS:数据库管理系统(用于管理数据库 ...

  10. Oracle学习笔记十一 游标

    游标的简介 游标的概念 游标是从数据表中提取出来的数据,以临时表的形式存放在内存中,在游标中有一个数据指针,在初始状态下指向的是首记录,利用fetch语句可以移动该指针,从而对游标中的数据进行各种操作 ...

随机推荐

  1. Chapter1:基础

    整本书的核心:语言的设计与实现 我们所看到的设计是显示的,语法定义的, 而实现是隐式的,决定了编译或运行时的行为. 了解设计的目的,可以推测实现的细节,也可以自己实现设计. 学习具体的实现,更充分的达 ...

  2. a标签跳转之前加点击事件

    ①在html标签中出现提示 <a href="http://www.baidu.com" onclick="if(confirm('确认百度吗?')==false) ...

  3. sau交流学习社区第三方登陆github--oauth来实现用户登录

    sau交流学习社区第三方登陆github--oauth来实现用户登录 最近在丰富nodejsBlog开发的“交流学习社区”(https://www.mwcxs.top)的其他功能以及修复一些bug. ...

  4. Maven把项目依赖的所有jar包都打到同一个jar中

    目录 1 使用maven-shade-plugin 2 推荐: 使用maven-assembly-plugin 3 扩展: Maven安装本地jar包到本地仓库 4 扩展: 手动生成jar包 5 扩展 ...

  5. springbatch的封装与使用

    springbatch 主要实现批量数据的处理,我对batch进行的封装,提出了jobBase类型,具体job需要实现它即可.Spring Batch 不仅提供了统一的读写接口.丰富的任务处理方式.灵 ...

  6. Python的垃圾回收机制(引用计数+标记清除+分代回收)

    一.写在前面: 我们都知道Python一种面向对象的脚本语言,对象是Python中非常重要的一个概念.在Python中数字是对象,字符串是对象,任何事物都是对象,而它们的核心就是一个结构体--PyOb ...

  7. FreeSql 过滤器使用介绍

    FreeSql.Repository 实现了过滤器,它不仅是查询时过滤,连删除/修改/插入时都会进行验证,避免数据安全问题. 过滤器 目前过滤器依附在仓储层实现,每个仓储实例都有 IDataFilte ...

  8. 扒一扒.NET Core的环境配置提供程序

    很久之前,在玩Docker的时候顺便扒了扒,最近,终于下定决心花了些时间整理并成文,希望能够给大家一些帮助. 目录 .NET Core中的配置 ASP.NET Core中的配置 扒一扒环境变量提供程序 ...

  9. 工程文件csproj使用编译条件指定属性

    csproj工程文件中有很多xml格式的属性,比如PropertyGroup.ItemGroup,某些属性操作默认是全部的或者是当前编译条件的而已,当我们想指定某些属性只在某个编译条件下发生时就可以通 ...

  10. 【MQ】消息队列及常见MQ比较

    一.什么是消息队列 我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用.消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰. ...