星辰日月00

欲多则心散,心散则志衰,志衰则思不达也!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 在PL/SQL程序中执行查询语句SELECT或数据操纵语句DML时,一般都可能产生或处理一组记录,
游标是为处理这些记录而分配的一段内存区。SQL语句对表进行操作时,每次可以同时对多条记录进行操作;
但是许多主语言(如C++、Delphi、java等开发工具)编制的应用程序,通常不能把整个结果集作为一个单元
来处理,这些应用程序需要有一种机制来保证每次只处理结果集中的一行,PL/SQL语言的游标提供了这种机制。
一、游标应用基础
 在PL/SQL程序中执行查询语句SELECT或数据操纵语句DML时,产生一记录集。根据记录集中记录数量的不同,
将游标分为两类,其中记录集只有单行数据时,系统自动进行定义游标,称为隐式游标。记录集中具有多选数据时,
需要由用户定义游标,称为显式游标。
1.(显示)游标使用的步骤
(1)声明游标
语法格式:

cursor cursor_name is select_statement;
--cursor_name是所定义的游标名,它是与某个查询结果集联系的符号名,要遵循oracle变量定义的规则。
declare
cursor student_cur
is
select name, dob
from students
where specialty = '计算机';

(2)打开游标
语法格式:Open cursor_name;
 当打开游标时,oracle会执行游标所对应的select语句,并且将select语句的结果暂时存放到结果集中。
为了在内存中分配缓冲区,并从数据库中检索数据,需要在pl/sql块的执行部分打开游标,当执行打开游标
操作后,系统首先检查游标定义中变量的值,然后分配缓冲区,执行游标定义时的select语句,将查询结果
在缓冲区中缓存。同时,游标指针指向缓冲区中结果集的第一个记录。
 注意:只有在打开游标时,才真正创建缓冲区,并从数据库检索数据;游标一旦打开,就无法再次打开,
除非先关闭;如果游标定义中的变量值发生变化,则只能在下次打开游标时才起作用。

open students_cur;

(3)读取数据
语法格式:fetch cursor_name into variable_name1, ..., variable_namen];
首先执行fetch语句时,游标指针指向第一条记录,对其操作完成后,游标指针指向下一条记录。
由于游标指定的内存缓冲区中可能有多条记录,因此读取游标的过程是一个循环的过程。

fetch students_cur into v_sname, v_dob;

(4)关闭游标
利用游标对其缓冲区中的数据处理完毕后,需要及时关闭游标,以释放游标所占用的系统资源。
语法格式:close cursor_name;

close students_cur;


2.游标属性

游标具有%isopen, %found, %notfound,和 %rowcount等四个发生,利用游标属性可以判断当前游标状态。
(1)%Isopen:布尔型,用于检测游标是否已经打开。如果游标已经打开,返回true,否则返回false。
(2)%found:布尔型,判断最近一次执行fetch语句后,是否从缓冲区中提取到数据,返回true,否则返回false。
(3)%notfound:与%found相反。
(4)%rowcount:数值型,返回到目前为止已经从游标缓冲区提取数据的行数。在fetch语句没有执行之前,该属性值为0。
使用隐式游标%found属性,sql%found;
使用显示游标%found属性,students_cur%rowcount。

二、游标应用
通过使用游标既可以逐行检索结果集中的记录,又可以更新或删除当前游标行的数据。
如果要通过游标更新或删除数据,在定义游标时必须要带有for update子句,
语法格式:

 cursor cursor_name is select_statement
for update [of column_reference] [nowait];
--for update子句用于在游标结果集数据上加行共享锁,以防止其他用户在相应行上执行dml操作;
--
of子句可选项,当select_statement引用了多个表时,选用of子句可以确定哪些表要加锁,
--
若没有选择of子句。则会在select_statement所引用的全部表上加锁。 nowait用于是否指定不等待锁。

1.浏览数据

set serveroutput on
declare
v_specialty students.specialty%type;
v_sname students.name%type;
v_dob students.dob%type;
cursor students_cur
is
select name, dob
from students
where specialty = v_specialty;
begin
v_specialty := '&specialty';
open students_cur;
dbms_output.put_line('学生姓名 出生日期');
loop
fetch students_cur into v_sanem, v_dob;
exit when students_cur%notfound;
dbms_output.put_line (v_sname || ' '|| v_dob);
end loop;
close students_cur;
end;


2.修改数据

declare
v_title teachers.title%type;
cursor teachers_cur
is
select title
from teachers
for update;
begin
open teachers_cur;
loop
fetch teachers_cur into v_title;
exit when teachers_cur%nofound;
when v_title = '教授' then
update teachers
set wage = 1.1 * wage where current of teachers_cur;
when v_title = '高工' or v_title = '副教授' then
update teachers
set wage = 1.1 * wage where current of teachers_cur;
else
update teachers
set wage = 1.1 * wage where current of teachers_cur;
end case;
end loop;
end;



3.删除数据
利用游标删除当前游标行数据,必须在delete语句中使用where current of子句。
语法格式:delete table_name where current of cursor_name;

declare
v_specialty students.specialty%type;
v_sname studs.name%type;
cursor students_cur
is
select name, specialty
from students
for update;
begin
open students_cur;
fetch students_cur into v_sname, v_specialty;
while students_cur%found loop
if v_specialty = '计算机' then
delete from students where current of students_cur;
end if;
fetch students_cur into v_sname, v_specialty;
end loop;
close studetns_cur;
end;

 

posted on 2012-03-28 08:07  星辰日月00  阅读(869)  评论(0编辑  收藏  举报