`
terran_li2008
  • 浏览: 200411 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ORACLE中的游标汇总

阅读更多
游标(Cursor
游标(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 游标;
cursor emp_cur ( p_deptid in number) is
set serveroutput on
declare
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);
emp_cur;
 end loop;
 close
 
 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隐式游标
不用明确建立游标变量,分两种:
1PL/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;
2CURSOR 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%FOUND
SQL%NOTFOUND 

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

. TRUE :INSERT 

. TRUE :DELETEUPDATE,至少有一行DELETEUPDATE. 

. TRUE :SELECT INTO至少返回一行 

SQL%FOUNDTRUE,SQL%NOTFOUNDFALSE.
 

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;
/

 

 
显式和隐式游标的区别:
尽量使用隐式游标,避免编写附加的游标控制代码(声明,打开,获取,关闭),也不需要声明变量来保存从游标中获取的数据
 
2REF 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 INT) IS
--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_cvCURSOR变量
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_cvweak 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 i 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;

 

 
 
 
3cursor ref cursor的区别
从技术底层看,两者是相同的。普通plsql cursor在定义时是“静态”的。而
Ref cursors可以动态打开。
例如下面例子:
Declare
typerc is ref cursor;
cursor c 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-游标使用汇总.doc

    oracle-游标使用汇总,觉得不错所以转了

    Oracle 遍历游标的四种方式汇总(for、fetch、while、BULK COLLECT)

     Oracle 遍历游标的四种方式(for、fetch、while、bulk collect+forall) 2.问题分析  我们可以把游标想象成一张表,想要遍历游标,就要取到游标的每行数据,所以问题的关键就成了:如何取到行数据? 3.解决方案 ...

    游标分类汇总行转列oracleplsql

    自己写的一个数据库语句,涉及游标,飞类汇总,行换列,适合入门的同学参考!

    XML Oracle Servlet 复习汇总(S2)

    2 Oracle:plsql,游标 6分 3 Oracle:sql命令 8分 4 Oracle:数据库创建,授权 6分 5 Oracle:plsql块 5分 6 Oracle:过程与函数 6分 7 Oracle:plsql块 6分 8 Oracle:plsql,过程与函数 8分 9 Oracle:建表,组合索引 6分...

    Oracle Exception汇总(自定义Oracle异常)

    Oracle Exception汇总(自定义Oracle异常) 使用方法举例: Exception When no_data_found then Dbms_output.put_line(‘no_data_found’); ACCESS_INTO_NULL 为对象赋值前必需初始化对象。对应ORA-06530错误。 CASE...

    Oracle经典SQL语句

    ORACLE经典语句汇总 -- 字符串左填充和右填充,默认填充空格 -- 产生1~99行数据,少于一位则补0 -- 刪除相同行 -- 随机数 -- 产生业务流水号 -- 查询某张表中有哪些字段 -- 自循环表中 由叶子节点查父节点 -- 查子...

    大数据Oracle理论+SQL+面试问题汇总+BI理论

    本课程适应从事大数据行业开发人员或数据库开发人员以及BI开发人员,其中包含有ORACLE的理论基础知识,OracleSQL语句详细讲解、面试问题汇总、BI理论知识。汇总了Oracle在开发中常用到的各种函数如分析函数、开窗...

    SQLServer与Oracle语法差异汇总.docx

    从存储过程 自定义函数格式 游标 变量 赋值 语句结束符 大小写 Select 语法 Update语法 Delete语法 动态SQL语句 TOP用法 等各方面对比两个数据库的差异

    ORACLE11G宝典.rar 是光盘里面的内容,书太厚咧没法影印啊

    并在Oracle11g的环境中,对书中的全部例子进行了运行(其中大部分例子都以具体操作界面的形式添加到书中),以给读者构造一个真实、有序、合理、坚实、正确和专业的Oracle知识结构。  《Oracle11g宝典》是Oracle...

    oracle数据库经典题目

    1.在多进程Oracle实例系统中,进程分为用户进程、后台进程和服务进程。 2.标准的SQL语言语句类型可以分为:数据定义语句(DDL)、数据操纵语句(DML)和数据控制语句(DCL)。 3.在需要滤除查询结果中重复的行时,必须...

    oracle常用操作SQL语句

    汇总oracle一些常用SQL语句,比如:用户解锁、修改用户密码、锁表、视图恢复、定时任务、物化视图、触发器、带参游标、常用函数、执行计划、字符串/时间各种运算、HTTP请求、SQL优化等

    SQL21日自学通

    在子查询中使用汇总函数140 子查询的嵌套141 相关子查询144 EXISTS ANY ALL 的使用147 总结151 问与答151 校练场152 练习153 第一周回顾154 预览154 第二周概貌155 这一周都讲些什么155 第八天操作数据156 目标...

    SQL必知必会(第3版)--详细书签版

    第9章 汇总数据 51 9.1 聚集函数 51 9.1.1 AVG()函数 52 9.1.2 COUNT()函数 53 9.1.3 MAX()函数 54 9.1.4 MIN()函数 54 9.1.5 SUM()函数 55 9.2 聚集不同值 56 9.3 组合聚集函数 57 9.4 小结 58 第10章 ...

    SQL必知必会(第3版 中文高清版)

    第9章 汇总数据  第10章 分组数据  第11章 使用子查询  第12章 联结表  第13章 创建高级联结  第14章 组合查询  第15章 插入数据  第16章 更新和删除数据  第17章 创建和操纵表  第18章 使用视图...

    SQL必知必会(第3版-PDF清晰版)part1

    第9章 汇总数据...... 51 9.1 聚集函数..... 51 9.1.1 AVG()函数..... 52 9.1.2 COUNT()函数..... 53 9.1.3 MAX()函数..... 54 9.1.4 MIN()函数..... 54 9.1.5 SUM()函数..... 55 9.2 聚集不同值..... 56 9.3 组合...

    亮剑.NET深入体验与实战精要2

    3.4.5 刷新页面的方法汇总 149 3.4.6 页面事件控制 150 3.4.7 在URL中传递中文的解决方案 152 3.4.8 增强用户体验的一些技巧 153 3.4.9 XHTML与HTML的区别 156 3.5 打造自己的页面基类PageBase 161 本章常见技术面试...

    亮剑.NET深入体验与实战精要3

    3.4.5 刷新页面的方法汇总 149 3.4.6 页面事件控制 150 3.4.7 在URL中传递中文的解决方案 152 3.4.8 增强用户体验的一些技巧 153 3.4.9 XHTML与HTML的区别 156 3.5 打造自己的页面基类PageBase 161 本章常见技术面试...

Global site tag (gtag.js) - Google Analytics