游标
游标的操作
- 步骤
- 定义游标
定义游标
语法
CURSOR cursor_name IS select_statement ;
说明
游标必须在PL/SQL块的声明部分进行定义;
游标定义时可以引用PL/SQL变量,但变量必须在游标定义之前定义;
定义游标时并没有生成数据,只是将定义信息保存到数据字典中;
游标定义后,可以使用cursor_name%ROWTYPE定义游标类型变量。
- 打开游标
打开游标
语法
OPEN cursor_name;
说明
检查变量的值
执行游标定义时对应的SELECT语句,将查询结果检索到工作区中。
游标指针指向第一个元组。
一旦游标打开,就无法再次打开,除非先关闭。
如果游标定义中的变量值发生变化,则只能在下次打开游标时才起作用。
- 检索游标
检索游标
语法格式
FETCH cursor_name INTO variable_list|record_variable;
说明
在使用FETCH语句之前必须先打开游标
对游标第一次使用FETCH语句时,游标指针指向第一条记录,因此操作的对象是第一条记录,使用后,游标指针指向下一条记录。
游标指针只能向下移动,不能回退。
INTO子句中的变量个数、顺序、数据类型必须与工作区中每行记录的字段数、顺序以及数据类型一一对应。
- 关闭游标
关闭游标
语法格式
CLOSE cursor_name;
说明
游标所对应的内存工作区变为无效,释放与游标相关的系统资源
声明一个检索emp表中雇员信息的游标,然后打开游标,并指定检索职务是’MANAGER’的雇员信息,接着使用 fetch…into语句和while循环读取游标中的所有雇员信息,最后输出读取的雇员信息。
DECLARE
Cursor cur_emp(var_job in varchar2:=‘SALESMAN’)
Is select empno,ename,sal
From emp
Where job=var_job;
Type record_emp is record
(var_empno emp.empno%type,
var_ename emp.ename%type,
var_sal emp.sal%type);
Emp_row record_emp;
BEGIN
open cur_emp(‘MANAGER’);
Fetch cur_emp into emp_row;
While cur_emp%found loop
Dbms_output.put_line(emp_row.var_ename||’的编号是’||
emp_row.var_empno||’,工资是’||emp_row.var_sal);
Fetch cur_emp into emp_row;
END LOOP;
CLOSE c_emp;
END;
显式游标的属性
%ISOPEN
布尔型。如果游标已经打开,返回TRUE,否则为FALSE。
%FOUND
布尔型,如果最近一次使用FETCH语句,有返回结果则为TRUE,否则为FALSE;
%NOTFOUND
布尔型,如果最近一次使用FETCH语句,没有返回结果则为TRUE,否则为FALSE;
%ROWCOUNT
数值型,返回到目前为止从游标缓冲区检索的元组数。
%BULK_ROWCOUNT(i)
数值型,用于取得FORALL语句执行批绑定操作时第i个元素所影响的行数。
声明一个游标,用于检索指定员工编号的雇员信息,然后使用游标的%found属性来判断是否检索到指定员工编号的雇员信息。
DECLARE
Var_ename varchar2(50);
Var_job varchar2(50);
Cursor cur_emp
Is select ename,job
From emp
Where empno=7499;
BEGIN
open cur_emp;
Fetch cur_emp into var_ename,var_job;
If cur_emp%found then
Dbms_output.put_line(‘编号是7499的雇员名称为:’||var_ename||’,
职务是:’||var_job);
Else
Dbms_output.put_line(‘无数据记录’);
End if;
END;
** 隐式游标**
概念
所有的SQL语句都有一个执行的缓冲区,隐式游标就是指向该缓冲区的指针,由系统隐含地打开、处理和关闭。隐式游标又称为SQL游标。
隐式游标主要用于处理INSERT、UPDATE,DELETE以及单行的SELECT…INTO语句,没有OPEN,FETCH,CLOSE等操作命令。
修改员工号为1000的员工工资,将其工资增加100。如果该员工不存在,则向emp表中插入一个员工号为1000,工资为1600的员工。
BEGIN
UPDATE emp SET sal=sal+100 WHERE empno=1000;
IF SQL%NOTFOUND THEN
INSERT INTO emp(empno,sal) VALUES(1000,1600);
END IF;
END;
或
BEGIN
UPDATE emp SET sal=sal+100 WHERE empno=1000;
IF SQL%ROWCOUNT=0 THEN
INSERT INTO emp(empno,sal) VALUES(1000,1600);
END IF;
END;
通过for语句循环游标
语法格式:
For var_auto_record in cur_name loop
Plsqlsentence;
End loop;
例:使用显式游标和for语句检索出部门编号是30
的雇员信息并输出。
SQL>set serveroutput on
SQL>declare
cursor cur_emp is
select * from emp
where deptno=30;
begin
for emp_record in cur_emp
loop
dbms_output.put(‘雇员编号:’||emp_record.empno);
dbms_output.put(‘:雇员名称:’||emp_record.ename);
dbms_output.put_line(‘:雇员职务:’||emp_record.job);
end loop;
end;
/
例:使用隐式游标和for语句检索出职务是销售员
的雇员信息并输出。
SQL>set serveroutput on
SQL>begin
for emp_record in(select empno,ename,sal from emp
where job=‘SALESMAN’)
loop
dbms_output.put(‘雇员编号:’||emp_record.empno);
dbms_output.put(‘:雇员名称:’||emp_record.ename);
dbms_output.put_line(‘:雇员工资:’||emp_record.sal);
end loop;
end;
/
预定义异常
例:使用select into语句检索emp表中部门编号为10的雇员记录信息,
然后使用“too_many_rows”预定义异常捕获错误信息并输出。
DECLARE
Var_empno number;
Var_ename varchar2(50);
Begin
Select empno,ename into var_empno,var_ename
From emp
Where deptno=10;
If sql%found then
Dbms_output.put_line(‘雇员编号:’||var_empno||’;雇员名称’
||var_ename);
End if;
Exception
When too_many_rows then
Dbms_output.put_line(‘返回记录超过一行’);
When no_data_found then
Dbms_output.put_line(‘无数据记录’);
End;
自定义异常
声明一个异常名称
e_integrity EXCEPTION;
将异常与一个Oracle错误号相绑定
PRAGMA EXCEPTION-INIT(e_integrity.-2291)
示例
DECLARE
e_deptno_fk EXCEPTION;
PRAGMA EXCEPTION_INIT(e_deptno_fk,-2292);
BEGIN
……
EXCEPTION
……
END;
异常处理过程
异常处理分3个步骤进行:
在声明部分为错误定义异常,包括非预定义异常和用户定义异常。
在执行过程中当错误产生时抛出与错误对应的异常。
在异常处理部分通过异常处理器捕获异常,并进行异常处理。
异常的捕获与处理
例如,查询名为SMITH的员工工资,如果该员工不存在,则输出“There is not such an employee!”;如果存在多个同名的员工,则输出其员工号和工资。
DECLARE
v_sal emp.sal%type;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE ename='SMITH';
DBMS_OUTPUT.PUT_LINE(v_sal);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('There is not such an emplyee!');
WHEN TOO_MANY_ROWS THEN
FOR v_emp IN (SELECT * FROM emp WHERE ename='SMITH')
LOOP
DBMS_OUTPUT.PUT_LINE(v_emp.empno||' '||v_emp.sal);
END LOOP;
END;