本节要点:
- 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;