游标管理

本节要点:

  • l  什么是游标
  • l  显式游标
  • l  隐式游标

1         什么是游标

游标的使用可以让用户像操作数组一样操作查询出来的数据集,这使得使用PL/SQL编程更加方便。实际上,它提供了一种从集合性质的结果中提取单条记录的手段。

1.1       游标的概念

可以简单地理解游标为指向结果集记录的指针,利用游标可以返回它当前指向的行记录(只能返回一行记录)。如果要返回多行,那么需要不断地滚动游标,把想要的数据查询一遍。用户可以操作游标所在位置行的记录。例如,把返回记录作为另一个查询的条件。

1.2       游标的种类

Oracle中游标分为静态游标和REF游标两类。其中,静态游标就像一个数据快照,打开游标后的结果集是对数据库数据的一个备份,数据不随着对表执行DML操作后改变。从这个特性来说,结果集市静态的。由于本人较懒,暂时不对REF游标做介绍。

静态游标包含如下两种类型:

显示游标:是指在使用之前必须有着明确的游标声明和定义,这样的游标定义会关联数据查询语句,通常会返回一行或多行。打开游标后,用户可以利用游标的位置对结果集进行检索,使之返回单一的行记录,用户可以操作此记录。关闭游标后,就不能再对结果集进行任何操作。显示游标需要用户自己写代码完成,一切由用户控制。

隐式游标:和显示游标不同,它被PL/SQL自动管理,也被称为SQL游标。由Oracle自动管理。该游标用户无法控制,但能得到它的属性信息。

2         显示游标

通过显示游标用户可以操作返回的数据,使得一些在编程语言中复杂的功能变得更容易实现。

游标语法:

CURSOR cursor_name

[(parameter_name datatype,…)]

   IS select_statement;

  • l  CURSOR cursor_name:声明游标,cursor_name是游标的名称
  • l  parameter_name:参数名称
  • l  datatype:参数类型
  • l  select_statement:游标关联的select语句,但该语句不能使select…into…语句

游标的使用步骤:

显示游标的使用顺序可以明确地分为声明游标、打开游标、读取数据和关闭游标四个步骤:

1)         声明游标:用来给游标命名并且使得游标关联一个查询

DECLARE CURSOR cursor_name IS SELECT_STATEMENT

2)         打开游标:游标中任何对数据的操作都是建立在游标被打开的前提下。并且游标一旦打开,其结果集都是静态的,也就是说,此时结果集不会反映出数据库中对数据进行的增加、删除、修改操作。

OPEN cursor_name

3)         读取数据:利用FETCH语句完成,它可以把游标指向位置的记录放入到PL/SQL声明的变量当中。正常的情况下,FETCH要和循环语句一起使用。

FETCH cursor_name INTO Record_Name

4)         关闭游标:释放资源,结果集中的数据将不能做任何操作。

CLOSE cursor_name

 

循环游标用于简化游标处理代码,当用户需要从游标中提取所有记录时使用。

语法:

FOR <record_index> IN <cursor_name>

LOOP

                <executable statements>

END LOOP;

 

示例:

declare

  v_name m_user.user_nm%type;/*声明v_name,与user_nm字段类型一致*/

  Cursor cur_stu Is/*定义游标cur_stu*/

     /*游标关联查询*/

    select t.user_nm from m_user t where t.user_owner_flg = 'M';

begin

  Open cur_stu;/*打开游标*/

  Loop

    /*利用Fetch语句从结果集中提取指针指向的当前行记录*/

    Fetch cur_stu Into v_name;

    Exit When cur_stu%NotFound;/*集合循环完成时退出循环*/

    dbms_output.put_line('学生姓名:' || v_name);

  End Loop;

  Close cur_stu;/*关闭游标*/

end;

示例:带参数的显示游标

DECLARE

  flag    VARCHAR2(20);

  s_code VARCHAR2(5);

  s_name    VARCHAR2(20);

  CURSOR stu(user_owner_flg VARCHAR2) IS

    SELECT t.user_cd, t.user_nm FROM m_user t WHERE t.user_owner_flg = flag;

BEGIN

  flag := '&flag';

  OPEN stu(flag);

  LOOP

    FETCH stu

      INTO s_code, s_name;

    EXIT WHEN stu%NOTFOUND;

    DBMS_OUTPUT.PUT_LINE(s_code || ' ' || s_name);

  END LOOP;

  CLOSE stu;

END;

3         隐式游标

没有显示游标一样的可操作性,但是也经常用到。

特点:

  • 在PL/SQL中使用DML语句时自动创建隐式游标
  • 隐式游标自动声明、打开和关闭,默认名称是SQL
  • Select或DML操作产生隐式游标
  • 隐式游标的属性值始终是最新执行的SQL语句

游标的属性有:

  • %FOUND – SQL 语句影响了一行或多行时为 TRUE
  • %NOTFOUND – SQL 语句没有影响任何行时为TRUE
  • %ROWCOUNT – SQL 语句影响的行数
  • %ISOPEN  - 游标是否打开,始终为FALSE

 

示例:只有在 DML 语句影响一行或多行时,才返回 True

BEGIN

  UPDATE m_user t SET t.user_nm = '张三丰' WHERE t.user_cd = '1';

  IF SQL%FOUNDTHEN

    DBMS_OUTPUT.PUT_LINE('表已更新');

  END IF;

END;

示例:如果 DML 语句不影响任何行,则返回 True

DECLARE

  v_id   m_user.user_cd%type := '&id';

  v_name m_user.user_nm%Type := '&name';

BEGIN

  UPDATE m_user SET user_nm = v_name WHERE user_cd = v_id;

  IF SQL%NOTFOUNDTHEN

    DBMS_OUTPUT.PUT_LINE('编号未找到。');

  ELSE

    DBMS_OUTPUT.PUT_LINE('表已更新');

  END IF;

END;

示例:返回 DML 语句影响的行数

begin

  update m_user t set t.user_nm = 'CHE' where t.user_cd = 1;

  if SQL%Found then

    dbms_output.put_line('修改记录数为:' || SQL%RowCount);

  else

    dbms_output.put_line('未找到相应记录');

  end if;

end;

示例:如果没有与SELECT INTO语句中的条件匹配的行,将引发NO_DATA_FOUND异常

DECLARE

  v_id   m_user.user_cd%type;

  v_name m_user.user_nm%type;

BEGIN

  v_id := '&id';

  SELECT t.user_nm INTO v_name FROM m_user t WHERE t.user_cd = v_id;

  DBMS_OUTPUT.PUT_LINE(v_name);

EXCEPTION

  WHEN NO_DATA_FOUND THEN

    DBMS_OUTPUT.PUT_LINE('课程未找到');

END;

示例:如果 SELECT INTO 语句返回多个值,将引发TOO_MANY_ROWS异常

DECLARE

  v_flag   m_user.user_owner_flg%type;

  v_name m_user.user_nm%type;

BEGIN

  v_flag := '&flag';

  SELECT t.user_nm INTO v_name FROM m_user t WHERE t.user_owner_flg = v_flag;

  DBMS_OUTPUT.PUT_LINE(v_name);

EXCEPTION

  WHEN TOO_MANY_ROWS THEN

        DBMS_OUTPUT.PUT_LINE('该查询提取多行');

END;

posted @ 2017-08-15 13:37  silvan_happy  阅读(295)  评论(0编辑  收藏  举报