PL/SQL游标使用

游标只是一个指向查询语句返回的结果的指针,因此在游标定义时将包含一个查询定义。当游标打开后,数据被接收到一块内存区域存储,直到游标关闭。

游标实际上指向的是一块内存区域,这块内存区域位于进程全局区内部,称为上下文区域,在上下文区域中包含如下3类信息

1.查询返回的数据行

2.查询所处理的数据的行号

3.指向共享池中的已分析的SQL语句

游标实际上指向一块内存区域

游标定义时并不会获取游标数据,只有在游标被打开后,游标相关的查询语句被执行,然后将检索到的结果保存到内存中。

游标结构示意图

游标指向PGA,上下文区

查询结果集

查询处理的行数

共享池中已分析的查询语句

使用游标例子

declare

emprow emp%ROWTYPE

cursor emp_cur

is

select * from emp where deptno is not null;

begin

open emp_cur;

loop

fetch emp_cur

into emprow

dbms_output.put_line(‘员工编号:‘

||emprow.empno

||‘ ‘

||‘员工名称:‘

||emprow.ename

);

exit when emp_cur%NOTFOUND;

end loop;

close emp_cur;

end;

游标分类

1.显式游标

2.隐式游标  也叫SQL游标

执行每一个DML操纵语句时,oracle都会在PGA中的一个上文区域中具有一个隐式的游标。

begin

update emp set comm = comm * 1.12 where empno = 7369;

dbms_output.put_line(SQL%ROWCOUNT || ‘行被更新‘);

if SQL%NOTFOUND

then

dbms_output.put_line(‘不能更新员工号为7369的员工!‘);

end if;

commit;

exception

when others

then

dbms_output.put_line(SQLERRM);

end;

定义游标类型

declare

cursor emp_cursor

is

select * from emp where deptno=20;

begin

null;

end;

不能把值赋给游标名或者在表达式中使用它,但是游标和变量有着同样的作用域规则

declare

v_deptno NUMBER;

cursor emp_cursor

is

select * from emp where deptno = v_deptno;

begin

v_deptno:=20;

open emp_cursor;

if emp_cursor%ISOPEN then

dbms_output.put_line(‘游标已经被打开‘);

end if;

end;

v_deptno是绑定变量,该变量必须在游标声明前之前进行声明,否则oracle会报错。游标的形式参数都必须IN模式,并且不能给游标的参数添加NOT NULL约束

declare

cusor emp_cursor(p_deptno in number)

is

select * from emp where deptno=p_deptno;

begin

open emp_cursor(20);

end;

可以指定return子句定义游标返回值的类型,返回值的类型一定要和返回的结果集的类型一致,因此返回值一般为记录类型或%ROWTYPE指定的表中的类型

declare

cursor emp_cursor(p_deptno in number)return emp%ROWTYPE

is

select * from emp where deptno=p_deptno;

begin

open emp_cursor(20);

end;

使用游标属性

1.%ISOPEN

判断对应的游标变量是否打开,如果游标变量打开,则返回true,否则返回false。

declare

cursor emp_cursor(p_deptno in number)

is

select * from emp where deptno=p_deptno;

begin

if not emp_cursor%ISOPEN then

open emp_cursor(20);

end if;

if emp_cursor%ISOPEN then

dbms_output.put_line(‘游标已经打开了‘);

else

dbms_output.put_line(‘游标还没有被打开!‘);

end if;

close emp_cursor;

end;

2.%FOUND

检查是否从结果集中提取到了数据

declare

emp_row emp%ROWTYPE;

cursor emp_cursor(p_deptno in number)

is

select * from emp where deptno=p_deptno;

begin

if not emp_cursor%ISOPEN

then

open emp_cursor(20);

end if;

if emp_cursor%FOUND is null

then

dbms_output.put_line(‘%FOUND属性为NULL‘);

end if;

loop

fetch emp_cursor

into emp_row;

exit when not emp_cursor%FOUND;

end loop;

close emp_cursor;

end;

3.%NOTFOUND属性

该属性与%FOUND属性相反,当没有从游标中提取到数据时,该属性返回True,否则返回False,与%Found一样

declare

emp_row emp%ROWTYPE;

cursor emp_cursor(p_deptno in number)

is select * from emp where deptno=p_deptno;

begin

open emp_row(20);

if emp_cursor%NOTFOUND is null;

then

dbms_output.put_line(‘%NOTFOUND属性为null‘);

end if;

loop

fetch emp_cursor

into emp_row;

exit when emp_cursor%NOTFOUND;

end loop;

close emp_cursor;

end;

4.%ROWCOUNT

用来返回到目前为止已经从游标中取出的记录的行数

declare

emp_row emp%ROWTYPE;

cursor emp_cursor(p_deptno in number)

is

select * from emp where deptno=p_deptno;

begin

open emp_cursor(20);

loop

fetch emp_cursor

into emp_row;

exit when emp_cursor%NOTFOUND;

dbms_output.put_line(‘当前已提取的行数为:‘||emp_cursor%ROWCOUNT ||‘行!‘);

end loop;

close emp_cursor;

end;

5.提取游标数据

declare

deptno dept.deptno%TYPE;

dname dept.dname%TYPE;

loc dept.loc%TYPE;

dept_row dept%ROWTYPE;

cursor dept_cur is select * from dept;

begin

open dept_cur;

loop

if dept_cur%ROWCOUNT<=4 then

fetch dept_cur into dept_row;

if dept_cur%FOUND then

dbms_output.put_line(dept_row.deptno||‘ ‘|| dept_row.dname||‘ ‘||dept_row.loc);

end if;

else

fetch dept_cur into deptno,dname,loc;

if dept_cur%FOUND then

dbms_output.put_line(deptno||‘ ‘||dname||‘ ‘||loc);

end if;

end if;

exit when dept_cur%NOTCOUND;

end loop;

close dept_cur;

end;

批量提取数据

因为fetch语句一次只能提取一行,并且提取只能是向前的,因此如果要重新提取已经提取过的数据,只有重新打开游标

可以使用BULK COLLECT批处理子句可以一次性将游标中的结果集保存到集合中,这样就可以在集合中进行前进和后退处理。

declare

type depttab_type is table of dept%ROWTYPE;

depttab depttab_type;

cursor deptcur is select * from dept;

begin

open deptcur;

fetch deptcur BULK COLLECT INTO depttab;

for i IN 1 ..depttab.count

loop

dbms_output.put_line(depttab(i).deptno

||‘ ‘

||depttab(i).dname

||‘ ‘

||depttab(i).loc

);

end loop;

close deptcur;

end;

bulk collect into 会一次把所有数据都提取到集合中,如果数据量特别大,并且使用varray这样的具有固定元素个数的集合时,可能需要限制每次提取的行数,可以使用fetch bulk collect into limit语句提取部分数据。

declare

type dept_type is varray(4) of dept%ROWTYPE;

depttab dept_type

cursor dept_cursor

is

select * from dept;

v_rows int :=4;

v_count int :=0;

begin

open dept_cursor;

loop

fetch dept_cursor bulk collect into depttab limit v_rows;

exit when dept_cursor%NOTFOUND;

dbms_output.put(‘部门名称:‘);

for i in 1 .. (dept_cursor%ROWCOUNT-v_count)

loop

dbms_output.put(depttab(i).dname ||‘ ‘);

end loop;

dbms_output.new_line;

v_count:=dept_cursor%ROWCOUNT;

end loop;

close dept_cursor;

end;

操纵游标数据

1.loop循环

declare

dept_row dept%ROWTYPE

cursor dept_cursor is select * from dept;

begin

open dept_cursor;

loop

fetch dept_cursor into dept_row;

exit when dept_cursor%NOTFOUND;

dbms_output.put_line(‘部门名称:‘||dept_row.dname);

end loop;

close dept_cursor;

end;

2.while循环

declare

dept_row dept%ROWTYPE;

cursor dept_cursor is select * from dept;

begin

open dept_cursor;

fetch dept_cursor into dept_row;

while dept_cursor%FOUND loop

dbms_output.put_line(‘部门名称:‘||dept_row.dname);

fetch dept_cursor into dept_row;

end loop;

close dept_cursor;

end;

3.游标for循环

declare

cursor dept_cursor is select * from dept;

begin

for dept_row in dept_cursor loop

dbms_output.put_line(‘部门名称:‘||dept_row.dname);

end loop;

end;

可以在需要传递参数时,可以直接在游标名后面加入参数值

for dept_row in dept_cursor(20) loop

可以直接在for语句的in子句中使用子查询,而不是显式的声明一个游标

begin

for dept_row in (select * from dept)loop

dbms_output.put_line(‘部门名称:‘||dept_row.dname);

end loop;

end;

修改游标数据

1.在游标的声明部分添加for update子句

2.子句是在update或delete 语句 中添加where  current of 子句

1.for update

会对用select语句提取出来结果进行锁定,相当于给结果集的行加了一把互斥锁,实行行级锁定。这样其他的用户就不能对当前游标行进行修改或删除。

例子:定义select语句中使用了for update来锁定deptno 和dname这两个列。

cursor dept_cursor is select * from dept for update deptno,dname;

2.where current of

在使用for update语句锁定了表中的行后,可以在update或delete语句中使用where current of子句来得到当前游标所检索出来的行

where current of cursorname;

cursorname是当前使用for update子句的游标的名称,用来更新游标数据。

where cursor of 子句检索的游标一定要有for update子句,并且游标要被打开且至少返回一行,不然oracle会触发错误。

使用for update与where current of 子句来更新emp表中部门编号为20的员工提成

declare

cursor emp_cursor(p_deptno in number)

is

select * from emp where deptno=p_deptno for update;

begin

for emp_row in emp_cursor(20)

loop

update emp

set comm = comm * 1.12

where cursor of emp_cursor;

end loop;

commit;

end;

commit语句必须放在循环语句的后面,否则会导致游标更新或删除失败。

使用游标删除数据

declare

cursor emp_cursor(p_empno in number)

is

select * from emp where empno = p_empno for update;

begin

for emp_row in emp_cursor(7369)

loop

delete from emp where cursor of emp_cursor;

end loop;

end;

游标变量

在前面定义一个游标,就为其绑定一个查询语句,这种游标称为静态游标。游标变量是另一种类型的游标,在定义时并不绑定到具体的查询,而是可以打开任何类型兼容的查询,灵活性相当大。

在PL/SQL中,指针是使用REF作为前缀进行定义的,因此游标变量类型就是REF cursor类型。

游标变量示例

declare

type emp_type is ref cursor return emp%ROWTYPE;

emp_cur emp_type;

emp_row emp%ROWTYPE;

begin

open emp_cur for select * from emp;

loop

fetch emp_cur into emp_row;

exit when emp_cur%NOTFOUND;

dbms_output.put_line(‘员工名称:‘||emp_row.ename);

end loop;

end;

静态游标与游标变量的一个区别是游标变量指向的是一个查询的工作区,而静态游标指向的是数据库中的一个命名的工作区。游标变量不依赖一个特定的工作区,这个工作区是动态的。当一个游标变量指向一个特定的工作区的时候,oracle会为它保留该存储空间。因此可以在运行时为游标变量赋值一个新的值,将它作为一个参数传递给本地和存储过程,使得子程序可以用一个方便的路径来集中检索数据。

声明游标变量类型

游标变量是一种引用类型,类似于C语言的指针。

REF表示为一个指针类型。

declare

type emp_type is ref cursor return emp%ROWTYPE;

type gen_type is ref cursor;

emp_type使用了return子句进行约束,又称为强类型的游标变量,任何使用这种类型的游标变量在使用fetch into 语句提取数据时,都必须要匹配return指定的数据结构。

gen_type没有使用return子句,又称为弱类型的游标变量,使用这种类型的游标变量没有与任何记录数据结构关联,使用这种类型的定义可以比强类型的游标变量提供更多的灵活性,使其可以用于任意的查询,匹配任意的记录类型。

定义游标变量

declare

type emp_type is ref cursor return emp%ROWTYPE;

type gen_type is ref cursor;

emp_cur emp_type;

gen_cur gen_type;

begin

open emp_cur for select * from emp where deptno=20;

end;

静态游标是一个指向具体结果集的常量,是一个具体的游标对象;而游标变量是一个指向游标对象的指针,它指向具体的游标对象

PGA             游标变量1           游标变量2

| |

|————————————

SGA 实际的游标对象 查询的结果

如果type语句中未指定return子句,则可以连续地打开多次,分别为其赋不同的查询select子句。

重新打开一个游标变量以前不需要关闭它,当用不同的查询语句打开同一个游标变量的时候,上一个查询将被丢弃掉。

declare

type emp_curtype is ref cursor;

emp_cur emp_curtype;

begin

open emp_cur for select * from emp;

open emp_cur for select empno from emp;

open emp_cur for select deptno from dept;

end;

处理游标变量异常

如何通过处理INVALID_CURSOR异常,将一个已经打开的游标变量赋给另一个未打开的游标变量

declare

type emp_curtype is ref cursor;

emp_cur1 emp_curtype;

emp_cur2 emp_curtype;

emp_row emp%ROWTYPE;

begin

open emp_cur1 for select * from emp where deptno=20;

fetch emp_cur1 into emp_row;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘||emp_row.deptno);

fetch emp_cur2 into emp_row;

exception

when invalid_cursor then

emp_cur2:=emp_cur1;

fetch emp_cur2 into emp_row;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘emp_row.deptno);

open emp_cur2 for select * from emp where deptno=30;

fetch emp_cur1 into emp_row;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘||emp_row.deptno);

end;

另一个常见的异常类型rowtype_mismatch异常。

declare

type emp_curtype is ref cursor;

emp_cur emp_curtype;

emp_row emp%ROWTYPE;

dept_row dept%ROWTYPE;

begin

open emp_cur for select * from emp where deptno=20;

fetch emp_cur into dept_row;

exception

when ROWTYPE_MISMATCH then

fetch emp_cur into emp_row;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘||emp_row.deptno);

end;

除了使用弱类型的游标变量定义方式,也可以使用SYS_REFCURSOR类型

declare

emp_cur SYS_REFCURSOR;

emp_row emp%ROWTYPE;

dept_row dept%ROWTYPE;

begin

open emp_cur for select * from emp where deptno=20;

fetch emp_cur into dept_row;

exception

when ROWTYPE_MISMATCH then

fetch emp_cur into emp_row;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘||emp_row.deptno);

end;

在包中使用游标变量

create or replace package emp_data_action as

type emp_type is ref cursor return emp%ROWTYPE;

procedure getempbydeptno(emp_cur in out emp_type,p_deptno number);

end emp_data_action;

create or replace package body emp_data_action as procedure getembydeptno(emp_cur in out emp_type,p_deptno number) is emp_row emp%ROWTYPE;

begin

open emp_cur for select * from emp where deptno=p_deptno;

loop

fetch emp_cur into emp_row;

exit when emp_cur%NOTFOUND;

dbms_output.put_line(‘员工名称:‘||emp_row.ename||‘部门编号:‘||emp_row.deptno);

end loop;

close emp_cur;

end;

end emp_data_action;

可以在包中声明游标类型,但是不能在包中声明游标变量

调用包中的过程:

declare

emp_cursors emp_data_action.emp_type;

begin

emp_data_action.getempbydeptno(emp_cursors,20);

end;

游标变量的限制

1.不能在包中声明游标变量

2.不能在创建表或创建视图的语句中把字段类型指定为ref cursor类型,数据库字段是不能存放游标变量值的

3.游标类型的参数不支持使用远程过程调用(RPC)将游标变量从一个服务器传递到另一个服务器。

4.不能用比较操作符来判断两个游标变量是否相等,不相等或者为NULL

5.不能为游标变量赋空值

6.不能将ref cursor 类型作为集合的元素类型,也就是说在索引表,嵌套表和变长数组中不能存放游标变量的值

7.不能将在游标中使用的游标for循环用在游标变量上,也就是说游标和游标变量不要试图互相替换。

时间: 2024-10-09 19:04:39

PL/SQL游标使用的相关文章

PL/SQL游标

PL/SQL游标:A:分类:1:隐式游标:非用户明确声明而产生的游标. 你根本看不到cursor这个关键字.2:显示游标:用户明确通过cursor关键字来声明的游标. B:什么是隐式游标:1:什么时候产生:会在执行任何合法的SQL语句(DML---INSERT UPDATE DELETE DQL-----SELECT)中产生.他不一定存放数据.也有可能存放记录集所影响的行数.如果执行SELECT语句,这个时候游标会存放数据.如果执行INSERT UPDATE DELETE会存放记录影响的行数.C

Oracle数据库PL SQL游标

PL SQL游标 将hregright表中不存在hrno的记录,用house表中的hrno填充(house唯一的时候) declare cursor house_cur is select h.regno,h.hrno from house h where h.hrno is not null group by h.regno,h.hrno having count(h.regno)=1; begin for house in house_cur loop update hregright r

PL/SQL 游标 (实验七)

PL/SQL 游标 emp.dept 目标表结构及数据 要求 基于部门表建立游标dept_cursor1,使用记录变量接收游标数据,输出部门表信息: 显示格式: 部 门 号: XXX 部门名称: XXX 所在位置: XXX 基于部门表建立游标dept_cursor2,使用标量变量接收游标数据,输出部门表信息: 显示格式:部门号:XXX 部门名称:XXX 所在位置:XXX 基于雇员表建立游标emp_cursor,根据用户输入的部门号,输出该部门薪水在5000元上的雇员姓名.薪水. 显示格式:雇员姓

PL/SQL 游标的使用详解

一:通过游标,PL/SQL 指向语句被分析以后的活动集 二:对于不同的SQL语句,游标的使用情况不同:1:非查询语句--隐式的2:结果是单行的查询语句--隐式的或显式的3:结果是多行的查询语句--显式的 三:游标属性1:%FOUND 2:%NOTFOUND 3:%ISOPEN 4:%ROWCOUNT 三:显式游标的用法四个步骤(1)定义一个游标名,以及与其相对应的SELECT 语句.语法:CURSOR cursor_name IS select_statement (2)打开游标.语法:OPEN

PL/SQL 游标的使用

 游标的使用 ①游标概念 为了处理SQL 语句,ORACLE 必须分配一片叫上下文( context area )的区域来处理所必需的信息, 当中包含要处理的行的数目.一个指向语句被分析以后的表示形式的指针以及查询的活动集(active set). 游标是一个指向上下文的句柄( handle)或指针. 通过游标,PL/SQL能够控制上下文区和处理语句时上下文区会发生些什么事情 ②显式游标处理 1.显式游标处理需四个PL/SQL步骤: 定义游标:就是定义一个游标名,以及与其相相应的SELECT

Oracle数据库之PL/SQL游标

1. 游标概念 字面意思是游动的光标,是指向上下文区域的句柄或指针. 在PL/SQL块中执行CRUD操作时,ORACLE会在内存中为其分配上下文区.用数据库语言来描述游标就是:映射在上下文区结果集中一行数据上的位置实体. 用户可以使用游标访问结果集中的任意一行数据,将游标指向某行后,即可对该行数据进行操作.游标为应用提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法,是设计嵌入式SQL语句的应用程序的常用编程方式. 在每个用户会话中,可以同时打开多个游标,其最大数量由数据库初

PL/SQL 游标详解

刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行.只是要注意用更新游标的时候,不能在游标期间commit. 否则会报ORA-01002: fetch out of sequence就是COMMIT导致的错误.在打开有for update的cursor时,系统会给取出的数据加上排他锁(exclusive), 这样在这个锁释放前其他用户不能对这些记录作update.delete和加锁.而我一旦执行了commit,锁就释放了,游标也变成无效的,再去fetch数据时就出现错误了.

Oracle笔记 九、PL/SQL 游标的使用

--演示隐式游标,系统自动声明,自动打开,自动使用并且自动关闭 begin update emp set sal = 1000; dbms_output.put_line('影响的行数:' || sql%rowcount); end;   rollback;   /*游标的使用方法: 第一步:声明游标 第二步:打开游标 第三步:使用游标进行循环操作 第四步:关闭游标*/   --普通游标,游标本身就是一个变量 declare --下面的这行代码声明了一个游标 cursor mycur is se

PL/SQL游标的使用

游标的使用语法 1).定义游标 declare cursor 游标名 [(参数名 参数类型[,参数名 参数类型])] is select statement; 2)打开游标 if not cursor_name%isopen then open cursor_name; end if; 3)使用游标读取数据 loop fetch cursor_name into variable; exit when cursor_name%notfound; --TODO task statements en