Oracle中的游标的原理和使用详解


逐行处理查询结果,以编程的方式访问数据

游标的类型:

1、隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标,名字固定叫sql。

2、显式游标:显式游标用于处理返回多行的查询。
3、REF 游标:REF 游标用于处理运行时才能确定的动态 SQL 查询的结果
隐式游标:
在PL/SQL中使用DML语句时自动创建隐式游标,隐式游标自动声明、打开和关闭,其名为 SQL,通过检查隐式游标的属性可以获得最近执行的 DML 语句的信息,隐式游标的属性有: %FOUND – SQL 语句影响了一行或多行时为 TRUE,%NOTFOUND – SQL 语句没有影响任何行时为TRUE,%ROWCOUNT – SQL 语句影响的行数,%ISOPEN - 游标是否打开,始终为FALSE

BEGIN
  UPDATE t_bjqk SET fBL = fBL - 2 WHERE fBJDM='1461';
  IF SQL%FOUND THEN
    dbms_output.put_line('这次更新了' || SQL%ROWCOUNT);
  ELSE
    dbms_output.put_line('一行也没有更新' );
  END IF;
END;
--SELECT * FROM t_bjqk;
在select中有两个中比较常见的异常: 1. NO_DATA_FOUND 2. TOO_MANY_ROWS
SQL> declare
  2  sname1 student.sname%TYPE;
  3  begin
  4    select sname into sname1 from student;
  5    if sql%found then
  6      dbms_output.put_line(sql%rowcount);
  7    else
  8      dbms_output.put_line('没有找到数据');
  9      end if;
 10      exception
 11        when too_many_rows then
 12          dbms_output.put_line('查找的行记录多于1行');
 13         when no_data_found then
 14            dbms_output.put_line('未找到匹配的行');
 15       end;
 16  /
查找的行记录多于1行
PL/SQL procedure successfully completed
 
SQL>
显式游标:

sqlserver与oracle的不同之处在于: 最后sqlserver会deallocate 丢弃游标,而oracle只有前面四步: 声明游标、打开游标、使用游标读取记录、关闭游标。
显式游标的使用:
declare
  sname varchar2( 20); --声明变量
  cursor student_cursor is select sname from student ; --声明游标
begin
  open student_cursor;                 --打开游标
  fetch student_cursor into sname;     --让游标指针往下移动
  while student_cursor%found           --判断游标指针是否指向某行记录
  loop --遍历
    dbms_output.put_line ('学生姓名' ||sname );
    fetch student_cursor into sname;
  end loop;
  close student_cursor;
end;
      
------------------------------------有参数游标-------------------------------
declare
  sname student.sname%type;
  sno student.sno%type;
  cursor student_cursor (input_sno number) is 
  select s.sname, s.sno from student s where s.sno > input_sno; --声明带参数的游标
begin
  sno := &请输入学号;                     --要求从客户端输入参数值,"&"相当于占位符;
  open student_cursor( sno);             --打开游标,并且传递参数
  fetch student_cursor into sname, sno;  --移动游标
  while student_cursor% found
  loop
    dbms_output.put_line ('学号为:' ||sno ||'姓名为:' ||sname );
    fetch student_cursor into sname,sno;
  end loop;
  close student_cursor;
end;


------------------------------------循环游标-------------------------------    
-- Created on 18-1月-15 by 永文
declare
  stu1 student%rowtype ;       --这里也不需要定义变量来接收fetch到的值
  cursor student_cursor is select * from student ;
begin
  open student_cursor;         --这里不需要开启游标
  for stu1 in student_cursor
  loop
    dbms_output.put_line ('学生学号:' ||stu1.sno ||'学生姓名:' ||stu1.sname );
    fetch student_cursor into stu1;   --也不需要fetch了
  end loop;
  close student_cursor;               --这里也不需要关闭游标
end;


------------------------------------使用游标更新行-------------------------------   
declare
stu1 student%rowtype ;
cursor student_cursor is select * from student s where s.sno in (2 ,3 ) for update;--创建更新游标
begin
  open student_cursor;
  fetch student_cursor into stu1;--移动游标
  while student_cursor%found --遍历游标,判断是否指向某个值
  loop
    update student set sage = sage + 10 where current of student_cursor;--通过游标中的信息更新数据
    fetch student_cursor into stu1;--移动游标
  end loop;
  close student_cursor;
end;
 

declare
  stu1 student%rowtype ;
  cursor student_cursor is select * from student s where s.sno in (2 ,3 ) for update;--创建更新游标
begin
  open student_cursor;
  -- fetch student_cursor into stu1;--移动游标
  -- while student_cursor%found--遍历游标,判断是否指向某个值
  loop
    fetch student_cursor into stu1 ;--移动游标
    exit when student_cursor %notfound ;
    update student set sage = sage + 10 where current of student_cursor;--通过游标中的信息更新数据
  end loop;
  close student_cursor;
end;


------------------------------------使用fetch ... bulk collect into-------------------------------   
declare
  cursor   my_cursor is select ename from emp where deptno= 10; --声明游标
  type   ename_table_type is table of varchar2 (10 );--定义一种表类型,表中的属性列为varchar2类型
  ename_table  ename_table_type;--通过上面定义的类型来定义变量
begin
  open   my_cursor; --打开游标
  fetch my_cursor bulk collect into   ename_table; --移动游标
  for   i in 1 ..ename_table.count  loop
     dbms_output.put_line(ename_table(i));
  end   loop ;
  close my_cursor;
end;
 
 
-----------------------------------显示游标题目--------------------------------------
 
SQL > select * from student ;
        XH XM
---------- ----------
         1 A
         2 B
         3 C
         4 D
 
SQL > select * from address ;
        XH ZZ
---------- ----------
         2 郑州
         1 开封
         3 洛阳
         4 新乡
         
完成的任务 :给表student添加一列zz ,是varchar2 (10 )类型;
再从address中,将zz字段的数值取出来,对应的插入到
student新增的zz列中。
即:得到的结果:student表中,是:
          XH XM         ZZ
         -- ---------- ------
          1 A          开封
          2 B          郑州
          3 C          洛阳
          4 D          新乡
 
 
declare
  stu1 student %rowtype ;
  add1 address %rowtype ;
  cursor student_cursor is select * from student for update; --声明更新游标
  cursor address_cursor is select * from address ;           --声明游标
begin
  open student_cursor ;                --打开游标
  fetch student_cursor into stu1;      --移动游标
  while student_cursor% found--判断游标是否指向某条记录
  loop
    open address_cursor ;              --打开另外一个游标
    fetch address_cursor into add1 ;   --移动游标
    while address_cursor %found--判断游标是否指向某条记录
    loop
      if add1.xh = stu1.xh then--判断两个游标所指向的记录中xh的值是否相等
        update student s set s.zz = add1.zz where current of student_cursor; --假如相等就更新游标所指向的记录值
      end if;
      fetch address_cursor into add1 ; --移动游标
    end loop;
    close address_cursor ;             --关闭游标
    fetch student_cursor into stu1 ;   --移动游标
  end loop;
  close student_cursor ;               --关闭游标
end;
REF游标也叫动态游标:
qREF 游标和游标变量用于处理运行时动态执行的 SQL 查询 q创建游标变量需要两个步骤: q声明 REF 游标类型 q声明 REF 游标类型的变量 q用于声明 REF 游标类型的语法为:
TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>];
-----------------------------------ref游标---------------------------------
declare
  type ref_cursor  is ref cursor; --声明一个ref游标类型
  tab_cursor ref_cursor ;--声明一个ref游标
  sname student.xm %type ;
  sno student.xh %type ;
  tab_name varchar2 (20 );
begin
  tab_name := '&tab_name'; --接收客户输入的表明
  if tab_name = 'student' then
    open tab_cursor for select xh ,xm  from student ; --打开ref游标
    fetch tab_cursor into sno ,sname ;--移动游标
    while tab_cursor %found
    loop
      dbms_output.put_line ('学号:' ||sno ||'姓名:' ||sname );
      fetch tab_cursor into sno ,sname ;
    end loop;
    close tab_cursor ;
  else
    dbms_output.put_line ('没有找到你想要找的表数据信息' );
  end if;
end;
 
  
-----------------------------------ref游标题目---------------------------------
SQL > select * from student ;
        XH KC
---------- ----------
         1 语文
         1 数学
         1 英语
         1 历史
         2 语文
         2 数学
         2 英语
         3 语文
         3 英语
9 rows selected
 
SQL >       
完成的任务 :
生成student2表 (xh number, kc  varchar2 (50 ));
对应于每一个学生,求出他的总的选课记录,把每个学生的选课记录插入到student2表中。
即,student2中的结果如下:
                      XH KC
                 --- -------------------------------------------
                       1 语文数学英语历史
                       2 语文数学英语
                       3 语文英语
 
create table student2 (xh number, kc varchar2 (50 ));
 
declare
  kcs varchar2 (50 );
  kc varchar2 (50 );
  type ref_cursor is ref cursor; --声明一个ref游标类型
  stu_cursor ref_cursor ;--定义一个ref游标类型的变量
  type tab_type is table of number; --声明一个table类型
  tab_xh tab_type ;--定义一个表类型的变量
  cursor cursor_xh is select distinct( xh) from student; --声明一个游标
begin
  open cursor_xh; --打开游标
  fetch cursor_xh bulk collect into tab_xh; --提取数据到表中
  for i in 1 .. tab_xh.count
  loop
    kcs :='' ;
    open stu_cursor for select kc from student s where s.xh = tab_xh(i ); --打开ref游标
    fetch stu_cursor into kc ; --移动游标
    while stu_cursor %found
    loop
      kcs := kc ||kcs ; --连接字符串使用||而不是+
      fetch stu_cursor into kc ; --移动游标
    end loop;
    insert into student2 (xh , kc ) values( i, kcs);
    close stu_cursor ;
  end loop;
  close cursor_xh ;
end;



  • 10
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彖爻之辞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值