游标(Cursor):用来查询数据库,获取记录集合(结果集)的指针,可以让开发者一次访问一行结果集,在每条结果集上作操作。
    游标可分为:
    <!--[if !supportLists]-->l         <!--[endif]-->静态游标:分为显式(explicit)游标和隐式(implicit)游标。
<!--[if !supportLists]-->l         <!--[endif]-->REF游标:是一种引用类型,类似于指针。----也称为动态游标

1、静态游标1.1显式游标定义格式:   CURSOR 游标名 ( 参数 )  [返回值类型]  IS    Select 语句 ;open 游标;loop  fetch  游标  into 游标变量;exit   when 游标%notfound;end loop;close 游标;例子

set serveroutput on
declare
cursor emp_cur ( p_deptid in number) is
select * from employees where department_id = p_deptid;
 
l_emp employees%rowtype;
begin
 dbms_output.put_line('Getting employees from department 30');
open emp_cur(30);
 loop
  fetch emp_cur into l_emp;
  exit when emp_cur%notfound;
  dbms_output.put_line('Employee id '|| l_emp.employee_id || ' is');
  dbms_output.put_line(l_emp.first_name || ' ' || l_emp.last_name);
 end loop;
 close emp_cur;
 
 dbms_output.put_line('Getting employees from department 90');
open emp_cur(90);
 loop
 fetch emp_cur into l_emp;
  exit when emp_cur%notfound;
  dbms_output.put_line('Employee id '|| l_emp.employee_id || ' is');
  dbms_output.put_line(l_emp.first_name || ' ' || l_emp.last_name);
 end loop;
 close emp_cur;
end;
/
 

1.2隐式游标不用明确建立游标变量,分两种:1.PL/SQL中使用DML语言,使用ORACLE提供的名为“SQL”的隐示游标。举例:

declare
begin
 update departments    set  department_name=department_name where 1=2; dbms_output.put_line('update '|| sql%rowcount ||' records');
end;

2.CURSOR FOR LOOP,用于for  in loop 语句for 游标变量 in 游标 loop   end loop;用于静态游标中,不能用于动态游标,且不需要显示的打开、关闭、取数据、测试数据的存在、定义数据的变量等等。举例:

游标FOR循环,简化游标操作my_dept_rec 不需要声明
declare
begin 
 for my_dept_rec in ( select department_name, department_id from epartments)
 loop
  dbms_output.put_line(my_dept_rec.department_id || ' : ' || my_dept_rec.department_name);
 end loop;
end;
/

1.3静态游标常用属性:显式游标属性: %FOUND:变量最后从游标中获取记录的时候,在结果集中找到了记录。%NOTFOUND:变量最后从游标中获取记录的时候,在结果集中没有找到记录。%ROWCOUNT:当前时刻已经从游标中获取的记录数量。%ISOPEN:是否打开。 隐式游标属性: SQL%FOUNDSQL%NOTFOUND    

在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是: 

. TRUE :INSERT 

. TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE. 

. TRUE :SELECT INTO至少返回一行 

当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE. 

SQL%ROWCOUNT 

   在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT             INTO语句,如果执行成功,SQL%ROWCOUNT的值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.

SQL%ISOPEN 

 SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%ISOPEN总是FALSE,这是因为隐式游标在DML语句执行时打开,结束时就立即关闭。

Declare
 /* 定义静态游标 */
 Cursor emps is
 Select * from employees where rownum<6 order by 1;
 
 emp employees%rowtype;
 Row number :=1;
Begin
 Open emps;  /* 打开静态游标 */
 Fetch emps into emp;  /* 读取游标当前行 */
 Loop
  If emps%found then
   Dbms_output.put_line('Looping over record '||row|| ' of ' || emps%rowcount);
   Fetch emps into emp;
   Row := row + 1;
  Else if emps%notfound then
   Exit; 
  End if;
 End loop;
 
 If emps%isopen then
  Close emps;   /*  关闭游标  */
 End if;
End;
/

显式和隐式游标的区别:

尽量使用隐式游标,避免编写附加的游标控制代码(声明,打开,获取,关闭),也不需要声明变量来保存从游标中获取的数据

2、REF CURSOR游标

动态游标,在运行的时候才能确定游标使用的查询。可以分为:
<!--[if !supportLists]-->l         <!--[endif]-->强类型(限制)(Strong REF CURSOR),规定返回类型
<!--[if !supportLists]-->l         <!--[endif]-->弱类型(非限制)(Weak REF CURSOR),不规定返回类型,可以获取任何结果集。

定义格式:TYPE ref_cursor_name IS REF CURSOR [RETURN return_type]   cursor   ref_cursor_name  open cursor for  select ......from (多个open for 同时用时 ,不需要有关闭游标的语句)例如:Declare  Type refcur_t is ref cursor; Type emp_refcur_t is ref cursor return employee%rowtype;Begin Null;End;/ 强类型举例:

declare
 --声明记录类型
 type emp_job_rec is record(
  employee_id number,
  employee_name varchar2(50),
  job_title varchar2(30)
 );
 --声明REF CURSOR,返回值为该记录类型
 type emp_job_refcur_type  is  ref  cursor  return emp_job_rec;
 --定义REF CURSOR游标的变量
 emp_refcur  emp_job_refcur_type;
 emp_job  emp_job_rec;
begin
 /*  打开动态游标 */ 
 open emp_refcur for
  select e.employee_id, e.first_name || ' ' ||e.last_name "employee_name",
    j.job_title
  from employees e, jobs j
  where e.job_id = j.job_id and rownum < 11 order by 1;
 /*  取游标当前行  */
 fetch emp_refcur into emp_job;
 while emp_refcur%found loop
  dbms_output.put_line(emp_job.employee_name || '''s job is ');
  dbms_output.put_line(emp_job.job_title);
  fetch emp_refcur into emp_job;
 end loop;
end;
/
 

指定了retrun 类型,CURSOR变量的类型必须和return 类型一致。例子:

CREATE OR REPLACE PACKAGE emp_data AS
TYPE empcurtyp IS REF CURSOR RETURN emp%rowtype;
--定义Strong REF CURSOR
PROCEDURE open_emp_cv(emp_cv IN OUT empcurtyp, choice INT);
--根据不同的choice选择不同的CURSOR
PROCEDURE retrieve_data(choice INT);
--通过调用procedure open_emp_cv,返回指定的结果集。
END emp_data;
 
CREATE OR REPLACE PACKAGE BODY emp_data AS
 
PROCEDURE open_emp_cv(emp_cv IN OUT empcurtyp, choice INTIS
--emp_cv作为传入/传出的CURSOR PARAMETER
BEGIN
IF choice = 1 THEN
OPEN emp_cv FOR  SELECT * FROM emp WHERE empno < 7800;
ELSIF choice = 2 THEN
OPEN emp_cv FOR SELECT * FROM emp WHERE SAL < 1000;
ELSIF choice = 3 THEN
OPEN emp_cv  FOR SELECT * FROM emp WHERE ename like 'J%';
END IF;
END;
 
PROCEDURE retrieve_data(choice INT) IS
return_cv empcurtyp;
--定义传入open_emp_cv的CURSOR变量
return_row emp%ROWTYPE;
invalid_choice EXCEPTION;
BEGIN
--调用 procedure OPEN_EMP_CV
open_emp_cv(return_cv, choice);
 
IF choice = 1 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with empno less t han7800');
ELSIF choice = 2 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with salary less than 1000');
ELSIF choice = 3 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with name starts with ''J''');
ELSE
RAISE invalid_choice;
END IF;
 
LOOP
FETCH return_cv   INTO return_row;
EXIT WHEN return_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(return_row.empno || '--' || return_row.ename || '--' ||
return_row.sal);
END LOOP;
 
EXCEPTION
WHEN invalid_choice THEN
DBMS_OUTPUT.PUT_LINE('The CHOICE should be in one of (1,2,3)!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Errors in procedure RETRIEVE_DATA!');
END;
 
END emp_data;
 

执行:SQL> EXEC emp_data.retrieve_data(1);SQL> EXEC emp_data.retrieve_data(2);SQL> EXEC emp_data.retrieve_data(3);SQL> EXEC emp_data.retrieve_data(34); 使用Weak REF CURSOR例子

create or replace procedure open_cv(choice IN INT, return_cv OUT SYS_REFCURSOR) is
--参数return_cv为weak REF CURSOR,利用SYS_CURSOR来定义
/*使用SYS_REFCURSOR可以使变量any_cv跟任何weak REF CURSOR类型匹配。  */
begin
if choice = 1 then
open return_cv for 'select * from emp';
elsif choice = 2 then
open return_cv for 'select * from dept';
end if;
end open_cv;
 
CREATE or replace procedure retrieve_data(choice IN INT) is
emp_rec emp%rowtype;
dept_rec dept%rowtype;
return_cv SYS_REFCURSOR;
invalid_choice exception;
 
BEGIN
if choice=1 then
dbms_output.put_line('employee information');
open_cv(1,return_cv); --调用procedure open_cv;
loop
fetch return_cv into emp_rec;
exit when return_cv%notfound;
dbms_output.put_line(emp_rec.empno||'-'||emp_rec.ename||'-'||emp_rec.sal);
end loop;
elsif choice=2 then
dbms_output.put_line('department information');
open_cv(2,return_cv);
 
loop
fetch return_cv into dept_rec;
exit when return_cv%notfound;
dbms_output.put_line(dept_rec.deptno||'-'||dept_rec.dname||'-'||dept_rec.loc);
end loop;
else
raise invalid_choice;
end if;
 
exception
when invalid_choice then
dbms_output.put_line('The CHOICE should be one of 1 and 2!');
when others then
dbms_output.put_line('Errors in procedure retrieve_data');
END retrieve_data;

执行:SQL> exec retrieve_data(1);SQL> exec retrieve_data(2);  用REF CURSOR实现BULK功能1. 可以加速INSERT, UPDATE, DELETE语句的执行,也就是用FORALL语句来替代循环语句。2. 加速SELECT,用BULK COLLECT INTO 来替代INTO。 SQL> create table tab2  as select empno ID, ename NAME, sal SALARY from emp where 1=2;

create or replace procedure REF_BULK is
/*  定义复杂类型 */
type empcurtyp  is ref cursor;
type idlist  is table of emp.empno%type;
type namelist  is table of emp.ename%type;
type sallist  is table of emp.sal%type;
  /* 定义变量  */
emp_cv  empcurtyp;
ids  idlist;
names namelist;
sals sallist;
row_cnt number;
begin
open emp_cv for select empno, ename, sal from emp;
fetch emp_cv  BULK COLLECT  INTO ids, names, sals;
--将字段成批放入变量中,此时变量是一个集合
close emp_cv;
 
for in ids.first .. ids.last loop
dbms_output.put_line(' || ids(i) || ' || names(i) ||' salary=' || sals(i));
end loop;
 
FORALL  i  IN  ids.first .. ids.last
insert into tab2 values (ids(i), names(i), sals(i));
commit;
select count(*) into row_cnt from tab2;
dbms_output.put_line('-----------------------------------');
dbms_output.put_line('The row number of tab2 is ' || row_cnt);
end REF_BULK;

3、cursor 和 ref cursor的区别

从技术底层看,两者是相同的。普通plsql cursor在定义时是“静态”的。而

Ref cursors可以动态打开。

例如下面例子:
Declare
typerc is ref cursor;
cursor is select * from dual;
 
l_cursor rc;
begin
if ( to_char(sysdate,'dd') = 30 ) then
       open l_cursor for 'select * from emp';
elsif ( to_char(sysdate,'dd') = 29 ) then
       open l_cursor for select * from dept;
else
       open l_cursor for select * from dual;
end if;
open c;
end;
/
<!--[if !supportLists]-->l         <!--[endif]-->rc根据逻辑动态打开;而游标c定义好了只有就无法修改了。
<!--[if !supportLists]-->l         <!--[endif]-->ref cursor可以返回给客户端,cursor则不行。
<!--[if !supportLists]-->l         <!--[endif]-->cursor可以是全局的global ,ref cursor则必须定义在过程或函数中
<!--[if !supportLists]-->l         <!--[endif]-->ref cursor可以在子程序间传递cursor则不行。
<!--[if !supportLists]-->l         <!--[endif]-->cursor中定义的静态sql比ref cursor效率高所以ref cursor通常用在:向客户端返回结果集

游标-Oracle游标汇总的更多相关文章

  1. Oracle 游标

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

  2. Oracle 游标示例,带异常处理

    Oracle游标示例一则,带异常处理. DECLARE CURSOR c_dl IS SELECT ID, NSRSBH, WSPZXH, ZXYY_DM, HZRQ, SWJG_DM, GXSJ F ...

  3. Oracle游标--cursor_01-简单不带参数实现功能

    对于游标这个概念,可以理解为类似我们以前学习的jdbc的结果集对象, 我们可以使用游标对结果集从上到下进行遍历,获取每一行内容 首先我们要分析一下游标的分类 带参数的 书写函数的整体架构 定义游标 开 ...

  4. Oracle游标带参数

    Oracle游标是可以带参数的,而SqlServer的游标就不可以了 create or replace procedure a as cursor b(c_id int)is select * fr ...

  5. oracle 游标使用大全

    转:http://www.cnblogs.com/fjfzhkb/archive/2007/09/12/891031.html oracle的游标和例子! 游标-----内存中的一块区域,存放的是se ...

  6. Oracle 游标使用(转)

    这个文档几乎包含了oracle游标使用的方方面面,全部通过了测试 ; ; dbms_output.put_line(sql) loop dbms_output.put_line( ; ; ; r_te ...

  7. Oracle 游标使用全解(转)

    转自:http://www.cnblogs.com/sc-xx/archive/2011/12/03/2275084.html 这个文档几乎包含了oracle游标使用的方方面面,全部通过了测试 -- ...

  8. Oracle游标动态赋值

    1. oracle游标动态赋值的小例子 -- 实现1:动态给游标赋值 -- 实现2:游标用表的rowtype声明,但数据却只配置表一行的某些字段时,遍历游标时需fetch into到精确字段 CREA ...

  9. Oracle游标cursor1基础和隐式游标

    --指向表行的指针,一次一行,一般向前移动 Resultset --游标永远代代表的是一行数据. /* 使用步骤 第一步:声明游标,就像是声明一个变量样. 游标的关键字就是cursor. Declar ...

随机推荐

  1. Xamarin android PreferenceActivity 实现应用程序首选项设置(一)

    应用程序首选项屏幕 类似系统设置界面. PreferenceActivity 是另一种类型的Activity,通过PreferenceActivity 可以以最少量的工作显示某些Preference列 ...

  2. SQL SERVER 遇到Unable to find the requested .Net Framework Data Provider. It may not be installed. (System.Data)

    今天新装的SQLSERVER 2012 EXPRESS 用于客户端程序 安装完成后打开登陆SQLSERVER 一切正常 当查看表定义.视图结构时,弹出一下内容 Unable to find the r ...

  3. C#调用IOS推送

    C#调用IOS推送 使用的是 PushSharp 开源库 源码代码如下 点我

  4. linux内核中sys_poll()的简化分析

    app:poll or select; kernel: sys_poll(); do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,st ...

  5. 怎样下载安装Firebug和使用Firebug

    Firebug是基于火狐(FireFox)浏览器的一个插件,它的作用是给Web页面开发者一个很好的测试前端页面代码的工具.所以深受网页开发者或网页布局爱好者的喜爱.像我们用DIV+CSS和html所写 ...

  6. (转)C#与Android通过adb实现usb通讯

    转自:http://blog.csdn.net/linweidong/article/details/6273507 需求: Android的apk获取手机信息,把结果发给PC client 注意地方 ...

  7. 《WPF程序设计指南》读书笔记——第5章 Stack与Wrap

    1.StackPanel面板 using System; using System.Windows; using System.Windows.Input; using System.Windows. ...

  8. Foreign Exchange

     10763 Foreign ExchangeYour non-profit organization (iCORE - international Confederation of Revolver ...

  9. SPFA&邻接表 PASCAL

    题目来自CODE[VS]-->热浪 1557 热浪 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石       题目描述 Description 德克萨斯纯朴的民眾们这个 ...

  10. 【学习总结】【多线程】 多线程概要 & GDC & NSOperation

    基本需要知道的 :  进程 :  简单点来说就是,操作系统中正在运行的一个应用程序,每个进程之间是独立的,每个进程均运行在受保护的内存空间内 线程 :  一个进程(进程)想执行任务,必须有线程(所以, ...