游标

游标存在意义:解决“select *”返回空、多行记录问题,但凡select,就可能多行结果集,也就需要用游标。

游标分4步走:cursor、open、fetch、close

可能省略open、close,用for ... in ... loop ... end loop;

1、静态游标:

(1)隐式游标:

在PL/SQL中DML(select into、insert、update、delete)时,Oracle隐式定义一个叫SQL的游标,自动声明、打开、关闭。

①sql%found

如果DML语句影响一行或多行,则sql%found为true

例如:

declare

   empno emp.empno%type;

begin

   select empno into empno -- 对于DML之select into

   from emp

   where empno =7369;

   ifsql%foundthen

      dbms_output.put_line('有一行记录');-- 用sql%found、sql%notfound判断是否返回一行记录

  endif;

Exception

  when no_data_found then

    dbms_output.put_line('查询返回空行');-- 用no_data_found判断是否返回空行记录

  when too_many_rows then

dbms_output.put_line('查询返回多行');-- 用too_many_rows判断是否返回多行记录

When others then

dbms_output.put_line(‘系统错误');

end;

例如:

declare

total integer;

e_null exception;--自定义的异常

e_toomanyrow exception;

begin

select count(*) into total from emp where emp.deptno=20;

if total>1 then

raise e_toomanyrow;--抛出异常

elsif total<=0 then

raise e_null;

end if;

--捕获并处理异常

Exception when e_toomanyrow then

dbms_output.put_line('Exception:返回多行记录');

when e_null then

dbms_output.put_line('Exception:无返回记录');

when others then

dbms_output.put_line('Exception:其他异常');

end;

②sql%notfound

如果DML语句没有影响任何行,则sql%notfound为true

第一种情况:DML是insert、delete、update

例如:

declare

begin

   deletefrom emp

   where empno =47;

   ifsql%notfoundthen

      dbms_output.put_line('未找到值');

   else

      dbms_output.put_line('已经删除');

   endif;

end;

第二种情况:DML是select into

PL/SQL中的“select into”的结果必须“有且只有一行”,该行结果可以赋给列变量、或记录变量

例如:

declare

  type type_emp isrecord

  (

  empno emp.empno%type,

  ename emp.ename%type,

  dname dept.dname%type,

  sal emp.sal%type

  );

  v_emp type_emp;

begin

  select empno, ename, dname, sal into v_emp

  from emp innerjoin dept

  on emp.deptno = dept.deptno

  where ename ='SMITH';

  --if sql%notfound then

    --dbms_output.put_line('查无此人'); -- 永远执行不到,因为查询返回空行时触发no_data_found异常

  --else

    dbms_output.put_line(v_emp.empno||'*'||v_emp.ename||'*'||v_emp.dname||'*'||v_emp.sal);

  --end if;

exception

  whenno_data_foundthen

    dbms_output.put_line('查无此人');

  whenothersthen

    dbms_output.put_line(sqlerrm);

end;

注意:

如果查询返回空行,PL/SQL抛出no_data_found异常;

如果查询返回多行,PL/SQL抛出too_many_rows异常;

所以在DML之“select into”引发异常时,不能使用sql%notfound属性查看DML是否影响了行。

③sql%rowcount 

declare

  empno emp.empno%type;

begin

  select empno into empno

  from emp

  where empno =7788;

  ifsql%rowcount>0then

    dbms_output.put_line('从表中选择了'||sql%rowcount||'行');

  else

    dbms_output.put_line('从表中未选择行');

  endif;

end;

④sql%isopen

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

(2)显式游标

重点在“步骤”:定义游标,打开游标, 抓取数据,关闭游标;

①游标%found

如果最后一条fetch语句成功提取行,则“游标%found”为true

②游标%notfound

如果最后一条fetch语句未能提取行,则“游标%notfound”为true

例如:

declare

cursor cur is

select ename,job from emp;  --这里enamel,job 两列

item emp.ename%type;   --定义item是emp表ename列的类型

item2 emp.job%type;    --定义item2 是emp表job列类型。 这里声明的变量必须对性查询--出的列对应。

begin

open cur;

loop

fetch cur into item,item2;  --捕捉了游标cur 的元素放入,item,item2中。

 

exitwhencur%notfound;  -- 当cur游标都便利完就exit退出。

endloop;

dbms_output.put_line(item||item2);

 

close cur;                  --注意关闭游标

end;

 

③游标%isopen,判断该游标是否被打开;

例如:

Declare

   --声明一个游标

  cursor cur is 

  select* from emp where deptno =10;

  v_emp cur%rowtype;

begin

  ifnot cur%isopenthen

    open cur;--如果游标没有被打开,那么就代开游标

  endif;

--循环,从游标中抓取数据

  loop

    fetch cur into v_emp;

    exitwhen cur%notfound;--当最后一条数据被获取后,exit退出循环

    dbms_output.put_line(v_emp.ename||':'||v_emp.sal);

  endloop;

  close cur;--关闭游标

end;

④游标%rowcount:返回游标查询记录数;

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

例如:(上面例子多了几行代码) declare

  cursor cur is

  select*

  from emp

  where deptno =10;

  v_emp cur%rowtype;

  a number;

begin

  ifnot cur%isopenthen

    open cur;

  endif;

  loop

    fetch cur into v_emp;

    exitwhen cur%notfound;

    dbms_output.put_line(v_emp.ename||':'||v_emp.sal);

  endloop;

-----------------------------------------------------------

  --下面是sql%rowcount

  select empno into  a from emp where empno='7369';

  dbms_output.put_line(sql%rowcount);--如果查询sql 有记录数,此时返回1否则为null

  dbms_output.put_line(cur%rowcount);--返回游标查询的最终记录数

-----------------------------------------------------------

  close cur;

end;

例如:

declare

cursor cur(i varchar2)is

select*from emp where deptno=i ;

    item cur%rowtype;

 

begin

 

for r in cur('10')  -- 注意这里的in。。。 后面跟的是游标 cur 而不是 tiem

      --这里可以写成:for admin in cur(&部门编号);用通配符,使键盘键入内容。

loop

dbms_output.put_line(r.ename|| cur%rowcount);--其中cur%rowcount 是有标明%rowcount 显示游标序列

endloop;

end;

⑤使用显式游标更新或删除行:

declare

-- select语句必须只包括一个表

-- 某表不能是“含有distinct、order by的子查询”查询来的结果集(视图)

cursor 游标名 is select 某列 from 某表 for update[ of 某列];

变量 某表.某列%type;

变量 某表%rowtype;

变量 游标%type;

变量 游标%rowtype;

begin

open 游标;

loop

fetch 游标 into 变量;

exit when 游标%notfound;

if 某条件 then

-- update、delete语句只有在打开游标、提取特定行之后才能使用

-- update语句中使用的列必须出现在“select-for update of”语句中

update 某表 set 某列 = 某值 where current of 游标;

end if;

end loop;

close 游标;

commit;

end;

例如:

-- 如果sal < 2000,长工资1000

declare

   cursor cur is

       select sal from emp

      where sal <2000forupdate;

  cursor bbb is

       select*from emp;

begin

  for v_sal in cur

   loop

       update emp

       set sal = sal +1000

       wherecurrentof cur;

  endloop;

 

 Commit;

  for v_emp in bbb

  loop

    dbms_output.put_line(v_emp.ename||'*'||v_emp.sal);

  endloop;

end;

动态游标:

(1)弱类型游标

例如:

declare         -- //弱类型游标

   type cursor_type isrefcursor;

   cur cursor_type;

   temp emp%rowtype;

begin

    open cur for 

    select*from  emp;  

    loop

       fetch cur into temp;

       exitwhencur%notfound;

       dbms_output.put_line(temp.empno||temp.ename);

    endloop; 

end;

例如:

 declare

   type cur_type isrefcursor;-- 弱类型游标 通过is ref 定义

   cur   cur_type;

   v_emp emp%rowtype;

   v_dept dept%rowtype;

   selection varchar2(1):= upper('D');

 begin

   if selection ='E'then

     open cur for

      select*from emp;

     loop

       fetch cur into v_emp;

       exitwhen cur%notfound;

       dbms_output.put_line(v_emp.ename||':'||v_emp.sal);

     endloop;

     close cur;

   elsif selection ='D'then

     open cur for

       select*from dept;

     loop

       fetch cur intov_dept;

       exitwhen cur%notfound;

       dbms_output.put_line(v_dept.deptno||':'||v_dept.dname);

     endloop;

     close cur;

   else

     null;

   endif;

 end;

 

 

(2)强类型游标

例如:

declare      --强类型游标 强制返回内容

   type record_type isrecord(empno number,ename varchar2(20));

   type cursor_type isrefcursorreturn record_type;

   rec record_type;

   cur cursor_type;

begin

    open cur for 

    select empno,ename from  emp;  

    loop

       fetch cur into rec;

       exitwhen cur%notfound;

       dbms_output.put_line(rec.empno||' '||rec.ename);

    endloop; 

end;

例如:

  -- 用强类型游标显示员工姓名和工资

 declare

   type record_type isrecord(namevarchar2(10), sal number);-- 记录类型

   type cur_type isrefcursorreturn record_type;-- 强类型游标,将来必须返回record_type类型的结果集

   emp_record record_type;-- 记录类型变量

   emp_cur   cur_type;-- 强类型游标变量

 

 begin

   open emp_cur for

   select ename, sal from emp;-- 动态SQL两边的单引号可以省略,必须返回record_type类型的结果集

   loop

      fetch emp_cur into emp_record;-- 把record_type类型的结果集向record_type类型的变量中填充

      exitwhen emp_cur%notfound;

      dbms_output.put_line(emp_record.name||':'||emp_record.sal);

   endloop;

   close emp_cur;

 end;

Oracle学习笔记之游标详解的更多相关文章

  1. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  2. Oracle学习笔记十一 游标

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

  3. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  4. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  5. Struts2学习笔记(二)——配置详解

    1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...

  6. Struts2学习笔记二 配置详解

    Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...

  7. Android学习笔记之Activity详解

    1 理解Activity Activity就是一个包含应用程序界面的窗口,是Android四大组件之一.一个应用程序可以包含零个或多个Activity.一个Activity的生命周期是指从屏幕上显示那 ...

  8. [C#] 类型学习笔记二:详解对象之间的比较

    继上一篇对象类型后,这里我们一起探讨相等的判定. 相等判断有关的4个方法 CLR中,和相等有关系的方法有这么4种: (1) 最常见的 == 运算符 (2) Object的静态方法ReferenceEq ...

  9. vue.js学习笔记(二)——vue-router详解

    vue-router详解 原文链接:www.jianshu.com 一.前言 要学习vue-router就要先知道这里的路由是什么?为什么我们不能像原来一样直接用<a></a> ...

随机推荐

  1. 201521123113 《Java程序设计》第3周学习总结

    1. 本周学习总结 2.书面作业 Q1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; p ...

  2. 201521123072《java程序设计》第十周学习总结

    201521123072<java程序设计>第十周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异 ...

  3. MarkDown模板

    一个例子: 例子开始 1. 本章学习总结 今天主要学习了三个知识点 封装 继承 多态 2. 书面作业 Q1. java HelloWorld命令中,HelloWorld这个参数是什么含义? 今天学了一 ...

  4. (转载)Oracle12g安装图解与安装过程常见问题注意事项

    首附转载地址:http://jingyan.baidu.com/article/f96699bbab21c0894e3c1bf8.html 首先,点击"setup",建议以管理员身 ...

  5. rpm包管理

    库文件 linux上,库文件是非常重要的,因为很多的软件都不是将所有的自己在需要的函数库自己写好,而是将一部分自己软件特有的库文件自己写,通用的库文件全部动态链接到公共库上去,这样不仅节省空间,同时用 ...

  6. org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method test() on null context object

    前言 本文中提到的解决方案,源码地址在:springboot-thymeleaf,希望可以帮你解决问题. 至于为什么已经写了一篇文章thymeleaf模板引擎调用java类中的方法,又多此一举的单独整 ...

  7. birt-j脚本调试 & 动态sql的实现

    一个比较好的birt问题解决网址: http://www.myexception.cn/h/1335919.html 1,Birt的JavaScript脚本简单调试 Birt中的js脚本不能用aler ...

  8. Centos6.7安装chrome

    cd /etc/yum.repos.dwget http://people.centos.org/hughesjr/chromium/6/chromium-el6.repo yum install c ...

  9. 二、js的控制语句

    二.流程控制语句 ECMA-262规定了一组流程控制语句.语句定义了ECMAScript中的主要语法,语句通常由一个或者多个关键字来完成给定的任务.诸如:判断.循环.退出等.   语句的定义   在E ...

  10. 第5章 不要让线程成为脱缰的野马(Keeping your Threads on Leash) ----初始化一个线程

    使用线程的一个常见问题就是如何能够在一个线程开始运行之前,适当地将它初始化.初始化最常见的理由就是为了调整优先权.另一个理由是为了在SMP 系统中设定线程比较喜欢的 CPU.第10 章谈到 MFC 时 ...