PLSql之游标(cursor)重点

一、游标概念及意义

1、游标概念:游标本质是一块内存区域,由系统或用户以变量的形式定义,可以提高数据库数据处理速度。游标的工作机制是一种能从包括多行数据记录的结果集中每次提取一行记录的机制,即游标提供了在逐行的基础上操作表中数据的方法。

注意:类似于java中迭代器(iterator)

2、解决问题:数据库在并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现。

二、游标的类型

1、隐式游标:在 PL/SQL 程序中执行DML SQL 语句时自动创建隐式游标;

2、显式游标:显式游标用于处理返回多行的查询;

3、REF 游标:REF 游标用于处理运行时才能确定的动态 SQL 查询的结果;

三、隐式游标:

1、隐式游标概念:在PL/SQL中使用DML语句时自动创建隐式游标,隐式游标自动声明、打开和关闭,其名为 SQL,通过检查隐式游标的属性可以获得最近执行的 DML 语句的信息;

2、隐式游标的属性

(1)%FOUND:SQL 语句影响了一行或多行时为 TRUE;

(2)%NOTFOUND: SQL 语句没有影响任何行时为TRUE;

(3)%ROWCOUNT:SQL 语句影响的行数;

(4)%ISOPEN:游标是否打开,始终为false。

注意:忽略大小写即大小写都可以。

四、显示游标

(一)显示游标处理需要四个PL/SQL步骤:

1、定义(声明)游标:定义一个游标名以及与其对应的select语句。

(1)格式如下:

cursor  cursor_name[(parameter[, parameter]…)]    
    [return datatype]
is
    select_statement;

(2)参数说明:游标参数只能为输入参数,格式如下:parameter_name [IN] datatype

注意:in关键字可以省略,在指定数据类型时,不能使用长度约束。如NUMBER(4),CHAR(10) 等都是错误的。

(3)[return datatype]是可选的,表示游标返回数据的数据类型。如果选择有,则应该严格与select_statement中的选择列表在数据次序和数据类型上匹配一致。

注意:数据类型一般是记录数据类型或带“表名或者游标名%ROWTYPE”的数据类型。

2、 打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。

注意:如果游标查询语句中带有for update选项,open语句还将锁定数据库表中游标结果集合对应的数据行。

(1)格式如下:

open cursor_name[value1,value2,...];

注意:PL/SQL 程序不能用OPEN 语句重复打开一个游标。

3、提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中。 

(1)格式如下:

fetch cursor_name into {variable_list|record_variable};

注意:variable_list表示table属性定义的数组,数据类型需指定和数据库表中某个字段类型一致。语法:type 变量名词  is table of emp.ename%type index by binary_integer;

注意:record_variable表示表名或者游标名%rowtype属性用于定义record变量,类似定义一个类,该类可以直接调用数据库表中所有字段。

(2)fetch语句执行过程:执行FETCH语句时,每次返回一个数据行,然后自动将游标移动指向下一个数据行。当检索到最后一行数据时,如果再次执行FETCH语句,将操作失败,并将游标属性%NOTFOUND置为TRUE。所以每次执行完FETCH语句后,检查游标属性%NOTFOUND就可以判断FETCH语句是否执行成功并返回一个数据行,以便确定是否给对应的变量赋了值。继续处理,直到活动集合中没有记录;

4、 关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。

注意:关闭后的游标可以使用OPEN 语句重新打开。

(1)格式如下:

close cursor_name;

五、游标实例

注意:复制代码到sql developer执行或者复制到ed中执行时,可能会报错,原因可能是博客写的代码对半角全角的处理有问题,可以手动输入一遍,加强理解学习。

declare
   cursor c is  select * from emp;
   demo  c%rowtype;
begin
    open c;
    fetch c into demo;
    dbms_output.put_line(demo.ename);
    close c;
end;
------------------
declare
    cursor c is  select * from emp;
    v_emp  c%rowtype;
begin
    open c;
    loop
      fetch c into v_emp;
      exit when (c%notfound);
      dbms_output.put_line(v_emp.ename);
    end loop;
    close c;
end;
----------------------
declare
    cursor c is  select * from emp;
    v_emp c%rowtype;
begin
    open c;
    fetch c into v_emp;
    while (c%found) loop
      dbms_output.put_line(v_emp.ename);
      fetch c into v_emp;
    end loop;
    close c;
end;
-----------------

使用游标建议使用for循环(因为for循环不用fetch,)
declare
    cursor c is
       select * from emp;
begin
   for v_emp in c loop
        dbms_output.put_line(v_emp.ename);
    end loop;
end;

--带参数的游标
declare
   cursor c (v_deptno emp.deptno%type, v_job emp.job%type)
   is
     select ename, sal from emp where deptno = v_deptno and job = v_job;
begin
   for v_temp in c(30,'CLERK') loop
      dbms_output.put_line(v_temp.ename);
   end loop;
end;

--可更新的游标
declare
  cursor c
  is
    select * from emp2 for update;
begin
   for v_temp in c loop
      if (v_temp.sal < 2000) then
         update emp2 set sal = sal * 2 where current of c;
      elsif (v_temp.sal = 5000) then
         delete from emp2 where current of c;
      end if;
    end loop;
    commit;
end;

--For 循环游标
--(1)定义游标
--(2)定义游标变量
--(3)使用for循环来使用这个游标
declare
       --类型定义
       cursor c_job
       is
       select empno,ename,job,sal
       from emp
       where job='MANAGER';
       --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
       c_row c_job%rowtype;
begin
       for c_row in c_job loop
         dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
       end loop;
end;


      
--Fetch游标
--使用的时候必须要明确的打开和关闭

declare 
       --类型定义
       cursor c_job
       is
       select empno,ename,job,sal
       from emp
       where job='MANAGER';
       --定义一个游标变量
       c_row c_job%rowtype;
begin
       open c_job;
         loop
           --提取一行数据到c_row
           fetch c_job into c_row;
           --判读是否提取到值,没取到值就退出
           --取到值c_job%notfound 是false 
           --取不到值c_job%notfound 是true
           exit when c_job%notfound;
            dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
         end loop;
       --关闭游标
      close c_job;
end;

参考文档:

http://www.cnblogs.com/huyong/archive/2011/05/04/2036377.html

http://www.cnblogs.com/sc-xx/archive/2011/12/03/2275084.html

你可能感兴趣的:(数据库:Oracle,MySQL)