1.概述

上文PLSQL学习中提到的知识,可以发现,基本都可以通过Java等语言实现,而为了实现程序的可移植性,实际开发工作中我们也是如此做的。

那么PLSQL的重点是什么呢?接下来我们来介绍游标cursor的概念。

之前提到,在不使用显式游标的情况下,PLSQL的中select语句只能返回一条记录,那么我们如果想要返回多条记录,或者遍历整个结果集该如何实现呢。

这里我们可以通过cursor实现。

1.1 cursor是什么

cursor是光标,游标的意思。比如我们的鼠标的光标就是cursor。

那么在数据库中cursor是什么呢?

当运行DML(select,update,insert,delete)语句时,ORACLE会在内存中为其分配缓冲区(Context Area),PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域。

游标在运行DML语句时打开,完成后关闭。

通俗的说:

我们知道,select语句会产生一个结果集,而游标是指在这个结果集上的第一条记录的一个指针。

而我们每次取出(fetch)一条记录,cursor就会自动指向下一条记录。

如果学过Java的话,可以这样理解,cursor类似于Java中的迭代器iterator。

1.2 cursor作用

基于以上的理解,cursor自然就被用于:取出每一条记录,遍历结果集。

1.3 cursor的四个属性

cursor有如下四个属性:

%isopen:布尔类型。判断游标是否打开,打开为true。对于隐式游标而言,这个值总是false,因为隐式游标在DML语句执行时打开,结束时就立即关闭。

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

. TRUE :INSERT

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

. TRUE :SELECT INTO至少返回一行

%notfound:布尔类型。当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE

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

注:PLSQL中的布尔类型的值为null、true、false。

2.显式游标和隐式游标

在游标声明之前,我们来看下显式游标和隐式游标。

2.1 隐式游标

事实上,当我们在PLSQL中进行非查询(或者返回单条记录的查询)语句,如update、delete、insert等时,ORACLE 系统会自动地为这些操作设置游标并创建其工作区,并且隐式游标的名字为SQL,由ORACLE 系统定义。

对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。

PL/SQL管理隐式游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。

用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。

简单实例

对于如下一张表ljb_test,更新每个人的薪水:

set serveroutput on;

begin

update ljb_test set salary = salary + 1;

dbms_output.put_line('更新了'||SQL%rowcount||'行数据'); --must before commit

commit;

end;

/

结果如下:

这里需要指出的是:关于隐式游标的属性操作,必须在commit之前,可以尝试把打印输出放在commit之后,得到的结果是0。这里之所以结果加了2,是因为我实验了两次。

2.2 显式游标

当查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。

显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。

这里要做一个声明,我们所说的游标通常是指显式游标,而显式游标需要被声明。

2.2.1 cursor的声明、打开、关闭、从游标提取数据

声明游标

CURSOR cursor_name IS select_statement;

打开游标

OPEN cursor_name;

关闭游标

CLOSE cursor_name;

从游标提取数据

从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。

语法如下:

FETCH cursor_name INTO variable[,variable,...]

如:

set serveroutput on;

declare

cursor c is select * from ljb_test; --1.声明游标的时候Oracle不会从数据库中取数据

v_test c%rowtype;

begin

open c; --2.打开游标,此时从数据库中取数据,并把结果集放在内存中

fetch c into v_test; --3.获取数据,fetch的时候游标自动往下移动一格

dbms_output.put_line(v_test.name);

fetch c into v_test;

dbms_output.put_line(v_test.name);

close c; --4.关闭游标,清掉内存。成对编程

end;

/

命令行运行,结果如下:

2.2.2 遍历结果集

如果我们想要遍历整个测试表,显然需要通过循环来进行。

正常情况下如果遵循循环遍历游标应当遵从以下步骤:

1、打开游标

2、开始循环

3、从游标中取值

4、检查那一行被返回

5、处理

6、关闭循环

7、关闭游标

事实上,我们确实可以通过该方式实现,即通过while循环和do while循环。

但是,for循环却不无需这么复杂,这里我们重点介绍for循环。

上文提到,PLSQL中有三种循环,这里需要指出的是,使用游标遍历时,最简单最稳定的就是for循环,但另外两种循环仍然会做简单介绍。如下:

2.2.2.1 for循环遍历

FOR循环的游标按照正常的声明方式声明,但是不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。

for循环是最简单也是最不容易出错的方式,推荐采用for循环遍历。

set serveroutput on;

declare

cursor c is select * from ljb_test;

--无需在此声明变量v_test

begin

--无需显式打开游标

for v_test in c loop

--无需显式fetch

dbms_output.put_line(c%rowcount||'--'||v_test.name);

end loop;

--无需显式关闭游标

end;

/

九条记录全部被打印,运行结果如下:

2.2.2.2 while循环遍历

declare

cursor c is select * from ljb_test; --声明游标的时候Oracle不会从数据库中取数据

v_test c%rowtype;

begin

open c; --打开游标,此时从数据库中取数据,并把结果集放在内存中

fetch c into v_test; --获取数据,fetch的时候游标自动往下移动一格

while c%found loop

dbms_output.put_line(c%rowcount||'--'||v_test.name);

fetch c into v_test;

end loop;

close c; --关闭游标,清掉内存。成对编程

end;

/

九条记录被遍历,结果如下:

如果我们把fetch语句和打印语句调换一下位置,结果会怎样?

可以看到,第一个记录被跳过取,最后一个打印两边。原因是,我们第一次打印前fetch了两次,而最后一个虽然c无法fetch到数据,但是上一个的c%fetch仍然是true。

所以,采用while循环一定注意fetch和打印的顺序。do while类似。

2.2.2.3 do while循环遍历

declare

cursor c is select * from ljb_test; --声明游标的时候Oracle不会从数据库中取数据

v_test c%rowtype;

begin

open c;

loop

fetch c into v_test;

exit when(c%notfound);

dbms_output.put_line(c%rowcount||'--'||v_test.name); --如果顺序反了,就会最后一条记录打印两次

end loop;

close c; --关闭游标,清掉内存。成对编程

end;

/

2.2.3 含参游标

类似于函数,我们可以将参数传递给游标并在查询中使用。

CURSOR cursor_name[(parameter[,parameter],...)]

IS select_statement;

参数定义方式为:

Parameter_name [IN] data_type[{:=|DEFAULT} value]

需要注意的是:游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。

declare

cursor c(v_dep ljb_test.dep%type, v_salary ljb_test.salary%type)

is select * from ljb_test where dep = v_dep and salary = v_salary;

begin

for v_temp in c(3,4000) loop

dbms_output.put_line(v_temp.name);

end loop;

end;

/

结果如下:

2.4 可更新游标

declare

cursor c is select * from ljb_test for update; --添加for update即可

begin

for v_temp in c loop

if(v_temp.salary<3500) then

update ljb_test set salary = salary * 2 where current of c; --更新条件

elsif(v_temp = 5000) then

delete from ljb_test where current of c; --更新条件

end if;

end loop;

commit;

end;

/

oracle中的cursor属性有哪些,Oracle学习11:游标(cursor)--显式游标隐式游标、游标四个属性、循环遍历...相关推荐

  1. 资源放送丨《Oracle中为什么没有Double Write?Oracle支持原子写吗?》PPT视频

    点击上方"蓝字" 关注我们,享更多干货! 前段时间,墨天轮邀请数据库资深专家 李真旭(Roger) 老师分享了<Oracle中为什么没有Double Write?Oracle ...

  2. oracle中exist什么意思,oracle中not exists 是什么意思 , oracle数据库中exists的作用

    导航:网站首页 > oracle中not exists 是什么意思 , oracle数据库中exists的作用 oracle中not exists 是什么意思 , oracle数据库中exist ...

  3. oracle中执行动态sql语句吗,oracle中有没有可动态执行sql语句的函数

    oracle中有没有可动态执行sql语句的函数 关注:233  答案:2  手机版 解决时间 2021-03-05 15:53 提问者祗剩寂寞 2021-03-04 22:38 oracle中有没有可 ...

  4. oracle中 xD转义,【转】oracle X表汇总

    最早从那里看到关于比较详细的X$表的介绍,后来陆续从其他Oracle专家那里得到了不少信息.在Steve Adams 的书中对X$表多有提及,而且他的站点也是个资源比较丰富的地方.不过在中文Oracl ...

  5. oracle中触发器只能用于表吗,Oracle触发器的分类和使用

    Oracle触发器的分类和使用 摘要:在Oracle中,触发器是一种特殊的存储过程,它在发生某种数据库事件时由Oracle 系统自动触发.触发器通常用于加强数据的完整性约束和业务规则等,对于表来说,触 ...

  6. oracle中闪回和回滚,oracle闪回操作详解

    Oracle的闪回 oracle中为什么会有闪回呢!它的作用是什么呢?我们来学习一下闪回吧!闪回和回滚异曲同工之妙. 一闪回的介绍 (1)在Oracle的操作工程中,会不可避免地出现操作失误或者用户失 ...

  7. oracle中何时会用到join,Oracle中join用法的演示

    以下的文章主要介绍的是Oracle中join用法,如果你是其方面的新手,对Oracle中oin的实际用法很感兴趣,但是却找不到一些资料去对其进行更深入的了解的话,你不妨浏览以下的文章对其进行了解. O ...

  8. oracle中代表任意一个字符的,oracle 语法

    1.基本语法:SELECT *[列名 [[AS] 别名], 列名2...] FROM 表名 [[AS] 别名]; 2. 使用||做连接:Oracle中的字符串用单引号. 例:SELECT " ...

  9. oracle 中触发器的作用是什么,oracle创建触发器及作用举例

    --创建触发器及作用举例 create or replace trigger tri before delete on emp --在删除emp表数据之前需要做的事根据自己的业务去写,before是在 ...

  10. oracle 几种锁,oracle_基于oracle中锁的深入理解,ORACLE里锁有以下几种模式:0:no - phpStudy...

    基于oracle中锁的深入理解 ORACLE里锁有以下几种模式:0:none 1:null 空 2:Row-S 行共享(RS):共享表锁 3:Row-X 行专用(RX):用于行的修改 4:Share ...

最新文章

  1. oracle数据库备份方法主要有哪几种,Oracle数据库备份方法有哪三种?
  2. MIT提出Matlab插件mNeuron:实现深度模型神经元的可视化
  3. 成功解决AttributeError: module tensorflow.compat has no attribute v1
  4. 简述python中面向对象的概念_简述Python中的面向对象编程的概念
  5. baidu patchrom项目开发详细教程(Being updated)
  6. LSGO软件技术团队内部技术交流
  7. html5群组选择器,css选择器
  8. js 获取当前元素的父元素的父元素的id
  9. C++中在浏览器打开html文件
  10. hydra安装及使用
  11. Docker部署项目的步骤,按步骤一步一步来,一切都会成功
  12. Mark:SQL Server关于CAST和CONVERT的区别和用法
  13. 7. 如何创建 CSS
  14. java 通过身份证计算年龄性别
  15. 艺术与科技的跨界融合 Jya美学家电品牌发布
  16. java dao 单元测试,你应该如何单元测试DAO层
  17. 再见,2018俄罗斯世界杯!
  18. 我的Python心路历程 第十期 (10.10 股票实战可视化历史趋势)
  19. 如何将低dpi图片升级到300dpi
  20. 龙威ol服务器维护是什么意思,《龙威OL》六大职业定位介绍

热门文章

  1. libiconv字符集转换库使用方法
  2. 用php做居中金字塔,[菜鸟学php] php版自定义函数实现金字塔
  3. 911计算机专业基础综合,青岛大学10数据结构911计算机专业综合
  4. 12306一直提示网络有问题_教你怎么在12306官网订购火车票 火车票查询12306订购...
  5. hdu2069(Coin Change)
  6. Python 使用pdfplumber 提取PDF页面表格的内容
  7. mysql 备份脚本 linux,LINUX中MySQL如何按时备份脚本
  8. linux 编译链接出错,Qt编译和链接错误
  9. c语言 数组指针传递给函数_嵌入式开发-C语言-指针与数组
  10. java脚本含义_set -e在bash脚本中的含义是什么?