8.2.1游标的概念和类型
游标(CURSOR)存储于服务器端,当服务器执行了一个查询后,查询返回的记录集存放在光标中,通过光标上的操作可以把这些记录检索到客户端的应用程序。光标是一种变量,它对应于一个查询语句确定的结果集。它用于逐行处理表中的数据。游标必须在plsql块的declare部分声明光标(光标),与定义局部变量在同一个位置。
游标中包含一个数据行指针用来指向当前数据行
打开游标时指针指向第一行,使用 FETCH ... INTO 语句后指向下一行。
指针指到最后一条记录为止(实际上指针最后一条记录之后是不存在的为空,这里只是表示遍历完所有数据),此时游标的%FOUND属性值为FALSE。
游标分为显示游标、隐式游标、REF游标。
8.2.2显示游标
显示游标是用户声明和操作的一种游标,通常用于操作查询结果集(查询语句返回的查询结果)
显示游标的格式如下:
cursor 游标名(游标输入参数)
is select 语句
使用游标的过程格式如下:
--打开游标
OPEN cursor name;
--提取数据
FETCH cursor_name INTO variable1,variable...;
--关闭游标
CLOSE cursor name;
显示游标有4个属性:
%ISOPEN :游标打开。
%FOUND:变量最后从游标中获取记录的时候,在结果集中找到了记录。
%NOTFOUND :变量最后从游标中获取记录的时候,在结果集中没有找到记录。
%ROWCOUNT :返回到目前为止,已经从游标缓冲区中提取到数据的行数。
【例8-4】定义一个和表 sm_emp结构一致的游标,并输出职工姓名和工资。
具体代码如下:
--第八章\yb.sql
---建立职工工资表
create table SM_EMP
(
empid VARCHAR2(30),
name VARCHAR2(30),
salary NUMBER(6,2),
telno CHAR(8)
)
--插入数据
Insert into SM_EMP
select '1101','王海',3500,'8863976' from dual;
Inser into SM_EMP
select '1135','孙宁',5000,'8563923' from dual;
Inser into SM_EMP
select '1236','张欣',8000,'8763125' from dual;
commit;
--建立存储过程,取出游标的数据
create or replace procedure pro_curortest
is
V_ename VARCHAR2(30);
V_salary number(6,2);
CURSOR c_emp IS SELECT name,salary FROM sm_emp;
BEGIN
OPEN c_emp;
LOOP
FETCH c_emp INTO v_ename,v_salary;
--将游标中的字段的值fetch到变量中
EXIT WHEN c_emp%NOTFOUND;
--当游标中没有数据时跳出loop
DBMS_OUTPUT.PUT_LINE ('Sal of Employee ' || v_ename
|| ' is '|| v_salary);
END LOOP;
CLOSE c_emp;
END;
执行后,结果如图8-4所示。
图8-4使用游标显示表中数据。
游标中可以定义参数,游标参数只能指定数据类型,而不能指定长度。
【例8-5】定义一个和表 sm_emp结构一致的游标,该游标有如数参数职工号。根据
输入的职工号输出对应职工姓名。
建立存储过程代码如下:
--第八章\yb.sql
create or replace procedure pro_cursorcs
is
cursor emp_cursor(no number) is select name from SM_EMP where empid=no;
v_ename SM_EMP.name%type;
begin
open emp_cursor('1135');
loop
fetch emp_cursor into v_ename;
exit when emp_cursor%notfound;
dbms_output.put_line(v_ename);
end loop;
close emp_cursor;
end;
执行后,结果如图8-5所示。
图8-5输出职工工资表的姓名。
使用游标处理结果集时,可以配合使用FOR语句来完成。使用FOR语句遍历游标中的数据时,可以把它的计时器看做一个自动的RECORD类型变量,
FOR循环是为了简化游标使用过程而设计的。使用游标FOR循环检索游标时,游标的打开、数据提取、数据是否检索到的判断与游标的关闭都是Oracle系统自动进行的。
【例8-6】使用for 循环建立游标,求出职工工资表所有员工的总薪水。
建立存储过程代码如下:
--第八章\yb.sql
create or replace procedure pro_forcursor
Is
---定义游标
CURSOR c_emp IS
SELECT name,salary
FROM sm_emp
ORDER BY name;
v_tot_sal NUMBER (10,2);
BEGIN
v_tot_sal :=0;
--游标for循环,求出雇员的工资总数。
FOR r_emp IN c_emp LOOP
DBMS_OUTPUT.PUT_LINE ('Name:' || r_emp.name ||'salary:' || r_emp.salary);
v_tot_sal :=v_tot_sal +r_emp.salary;
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Total salary is'||v_tot_sal);
END;
执行后,结果如图8-6所示。
图8-6输出职工总的工资。
8.2.3隐性游标
对于非查询语句,如修改、删除操作,由Oracle 系统自动为这些操作设置游标并创建其工作区,这些由系统隐含创建的游标称为隐性游标,隐性游标的名字为SQL,这是由Oracle 系统定义的。
对于隐性游标的操作,如定义、打开、取值及关闭操作,都由Oracle 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。
【例8-7】删除职工工资表中工号1101的记录,然后输出该语句影响的行数。
匿名块代码如下:
--第八章\yb.sql
declare
num int:=0;
begin
delete from sm_emp where empid='1101';
if sql%notfound then
dbms_output.put_line('该行数据没有发现');
else
dbms_output.put_line('数据被发现并删除,影响的行数为:'||sql%rowcount);
end if;
end;
执行后,结果如图8-7所示。
图8-7输出结果影响的行数
8.2.4ref 游标
ref游标:动态关联结果集的临时对象,即在运行的时候动态决定执行查询。
ref游标主要分为两类,强类型和弱类型的,强类型的为带有RETURN语句的REF动态游标,弱类型为不带有RETURN语句的REF动态游标。
定义REF动态游标类型,格式如下:
TYPE <类型名> IS REF CURSOR
RETURN <返回类型>;
打开REF动态游标,格式如下:
OPEN <游标名> FOR <查询语句>
【例8-8】建立包,在该包中定义ref游标。然后建立存储过程 list,如果输入参数为1,则返回职工表数据,如果为其他值,则返回部门表数据。
建立职工表和部门表,插入数据代码如下:
--第八章\yb.sql
create table SM_EMP
(
empid VARCHAR2(30),
name VARCHAR2(30),
salary NUMBER(6,2),
telno CHAR(8)
);
--插入数据
insert into SM_EMP
select '021101','王海',3500,'8863976' from dual;
insert into SM_EMP
select '031135','孙宁',5000,'8563923' from dual;
insert into SM_EMP
select '041236','张欣',8000,'8763125' from dual;
commit;
create table department
(bmbh varchar2(10),
bmmc varchar2(20));
insert into department
select '1101','人力资源' from dual;
insert into department
select '1201','物流' from dual;
insert into department
select '1501','企业管理部' from dual;
commit;
建立一个包,在该包中定义一个ref游标,代码如下:
CREATE OR REPLACE PACKAGE globalPkg AUTHID CURRENT_USER AS
TYPE result_set IS REF CURSOR;
END globalPkg;
建立存储过程,代码如下:
create or replace procedure list(result_set in out sys_refcursor, which in number)
is
begin
--打开动态游标时在为它指定查询语句
--1就是返回员工表,其他就返回部门表
if which=1 then
open result_set for select * from sm_emp;
else
open result_set for select * from department;
end if;
end;
执行后,如果输入1,结果如图8-8所示。
图8-8显示职工表数据
执行后,如果输入2,如图8-9所示。