ORACLE 游标

一. PL/SQL 是用游标来管理 SQL 的 SELECT 语句的 . 游标是为了处理这些语句而分配的一大块内存 . 它提供了对一个结果集进行逐行处理的能力 , 可看作是一种特殊的指针 . 它与某个查询结果集相关联 , 可以指向结果集的任意位置 , 以便对指定位置的数据进行处理 . 使用它可以在查询数据的同时对数据进行处理 .

二. 游标的分类 : 静态游标和动态游标

 1. 在说明游标分类之前, 先说明一下PL/SQL 的两个操作, 游标属性, 变量属性

SET SERVEROUTPUT ON ;-- 此语句用于开启打印输出功能

DMBS_OUTPUT.PUT_LINE();-- 打印输出并换行.

%FOUND: 判断当前游标是否指向有效的一条行记录. 是则返回TRUE, 否则返回FALSE

%NOTFOUND: 与%FOUND 恰好相反.

%ISOPEN: 判断游标是否打开, 打开则返回TRUE, 否则返回FALSE.

%ROWCOUNT: 判断当前游标在所指向的结果集中提取的行数. 并非所有总记录数

%TYPE: 声明变量的类型与表中的某列的数据类型完全一致.%TYPE 声明有两个好处: 一是你不必知道某列的确切数据类型二是当某列的数据类型改变时不用修改变量的数据类型.

%ROWTYPE: 声明变量的数据类型与表中的行记录数据类型一致. 对于自定义的记录, 则必须声明自己的域.

 2. 静态游标:

静态游标又可以分为两类:

1) 隐式游标

隐式游标的特点:

- 隐式游标是由PL/SQL 来管理的, 即不需要声明游标语句, 也不需要OPEN,FETCH,CLOSE 操作

- 隐式游标中必须要有select cur_name into [ 变量名或其他数据类型]. 此句完成OPEN,FETCH,CLOSE 操作.

- 隐式游标只能返回一行记录, 如果无符合条件的记录将会出现NO_DATA_FOUND 异常. 如果出现多条记录将出现TOO_MANY_ROWS 异常.

- 隐式游标只能用SQL% 判断其游标属性

- 对于任何位置使用SQL%ISOPEN 结果都是FALSE, 隐式游标由PL/SQL 管理

- 对于在隐式游标位置前使用SQL%FOUND 或SQL%NOTFOUND, SQL%ROWCOUNT 结果值是NULL( 不确定值)

示例表:

表名:test

字段名

数据类型

可否为空

id( 序号)

number

N

name( 姓名)

varchar2(20)

N

zym( 专业名)

varchar(40)

Y

cj( 成绩)

number

Y

logdate( 记录日期)

date

Y

EG1: 验证隐式游标的特性

 set serveroutput on;-- 开启输出

declare

 no test.id%type;-- 声明变量no 的数据类型同test 表的id 列一致

 ename test.name%type;

 begin

 if sql%isopen then         -- 判断游标是否打开

 dbms_output.put_line(' cursor is openning');

 else

 dbms_output.put_line('cursor is closed');

 end if;

if sql%notfound then – 判断游标是否指向有效的行

 dbms_output.put_line('no value');

 else

 dbms_output.put_line(no||' '||ename);

 end if;

dbms_output.put_line(sql%rowcount);

dbms_output.put_line('---------------');

 

 select id ,name into no ,ename from test where cj=90;-- 隐式游标必-- 须使用INTO

 dbms_output.put_line(sql%rowcount);

 if sql%isopen then

 dbms_output.put_line(' cursor is openning');

 else

 dbms_output.put_line('cursor is closed');

 end if;

 if sql%notfound then

 dbms_output.put_line('no value');

 else

 dbms_output.put_line(no||' '||ename);

 end if;

 exception

 when no_data_found then

 dbms_output.put_line('no value');

when too_many_rows then

 dbms_output.put_line('too many rows');

 end;

执行结果为:

cursor is closed

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

1

cursor is closed

1001 qbnajj

去掉where 条件时的结果:

cursor is closed

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

too many rows

EG2: 使用%ROWTYPE

declare

 rowtype test%rowtype;

 begin

 select * into rowtype from test where cj=90;

 dbms_output.put_line(rowtype.name||' '||rowtype.cj);

 exception

 when no_data_found then

 dbms_output.put_line('no value');

 when too_many_rows then

 dbms_output.put_line('too many rows');

 end;

执行结果:

qbnajj 90

EG3: 自定义RECORD 数据类型

declare

 

 type r_type is record(name test.name%type ,cj test.cj%type);

 re_type r_type;

 begin

 select name,cj into re_type from test where cj=90;

 dbms_output.put_line(re_type.name||' '||re_type.cj);

 exception

 when no_data_found then

 dbms_output.put_line('no value');

 when too_many_rows then

 dbms_output.put_line('too many rows');

 end;

/

执行结果:

qbnajj 90

2) 显示游标

声明语法:

DECLARE

CURSOR cur_name( 参数名 数据类型) is select_satatements ;-- 游标名后-- 可带参数

BEGIN

OPEN cur_name;

FETCH cur_name into [ 变量或者其他数据类型];

-- 可用循环语句迭代输出游标所指向的结果集.

CLOSE cur_name;

END;

显示游标特性:

- 显示游标由用户定义, 并由用户来管理游标, 可返回多行记录.

- 通常使用显示游标需要遵守以下规则

 声明游标 -> 打开游标 -> 读取数据 -> 关闭游标

   但由于FOR IN LOOP 语句包含OPEN,FETCH,CLOSE 操作所以不在此例.

 - 查看游标属性时, 使用cur_name%.

EG:PL/SQL 演示

declare

 no test.id%type;

 ename test.name%type;

 cjs test.cj%type;

 cursor test_cur is

 select id,name from test where cj>=cjs;-- 可通过PL/SQL 绑定变量输-- 入值(&cjs)

 begin

 cjs:=50;

 for t_cur in test_cur

 loop

 no:=t_cur.id;

 ename:=t_cur.name;

 dbms_output.put_line(no||' '||ename);

 end loop;

 end;

执行结果:

chenjunhua 80

qbnajj 90

cjh 52

EG2: 利用带参数的存储过程演示

create or replace procedure test_proce(cjs in test.cj%type)

 as

 no test.id%type;

 ename test.name%type;

 cursor test_cur is

 select id,name from test where cj>=cjs;

 begin

 open test_cur;

 fetch test_cur into no,ename;

 while test_cur%found

 loop

 dbms_output.put_line(no||' '||ename);

 fetch test_cur into no,ename;-- 将游标指向下条记录, 否则为死循环.

 end loop;

 close test_cur;

 end test_proce;

 exec test_proce(50);

执行结果:

chenjunhua 80

qbnajj 90

cjh 52

EG3: 带参数的游标与上面的类似