现在的位置: 首页 > 综合 > 正文

(oracle数据库基础)第六章 游标和异常管理

2013年08月22日 ⁄ 综合 ⁄ 共 6057字 ⁄ 字号 评论关闭

游标的出现是为了解决从某一结果集中逐一读取一条记录。

 

--1.游标的类型:显式游标和隐式游标。

--2.显式游标:通过open(打开)fetch(读取)close(关闭)三个命令控制游标。

 

--****2.11 declare语句,语法:****--

cursor cursor_name[(parameter[,parameter]...)]

[return return_type]
is select_statement

--例子declare1:声明游标,对应的集合是表emp中所有的员工姓名

declare

  cursor c_emp_ename
isselect ename
from emp;

--例子declare2:声明游标,对应的集合是表emp中所有的员工信息

declare

  cursor c_emp
isselect *
from emp;

--例子declare3:声明游标,对应的集合是表emp中根据输入员工号而确定的员工信息

declare

  cursor c_emp(v_empno
number(4))
isselect *
from emp
where empno=v_empno;

 

--*****2.12 open语句,语法:*****--

open cursor_name;

 

--*****2.13 fetch语句从游标提取一行数据使用,每一次提取数据后,游标都指向结果集的下一行*****--

语法:fetch cursor_name
intovariable[,variable,...]

--例子fetch1:显示例子declare1中第一行信息

declare

  cursor c_emp_ename
isselect ename
from emp;

  v_ename emp.ename%type;

begin

  open c_emp_ename;

  fetch c_emp_ename
into v_ename;

  dbms_output.put_line(v_ename);

end;

--例子fetch2:显示例子declare1中游标所有信息

declare

  cursor c_emp_ename
isselect ename
from emp;

  v_ename emp.ename%type;

  v_count
binary_integer
;

begin

  selectcount(rowid)
into v_count
from emp;--rowid:伪列,表示表中每一行记录在数据文件中的物理地址。

  open c_emp_ename;

  --方法1

  /*loop

    fetch c_emp_ename into v_ename;

    dbms_output.put_line(v_ename);

    v_count := v_count-1;

    exit when v_count=0;

  end loop;*/

  --方法2

  for i
in1..v_count
loop--in后面的语句只有两个"."

    fetch c_emp_ename
into v_ename;

    dbms_output.put_line(v_ename);

  endloop;

end;

   

--*****2.14close语句,语法*****--

close cursor_name;

--例子close1:在emp表中,计算所有员工的工资

--select sum(sal) from emp;

declare

  cursor c_emp_sal
isselect sal
from emp;

  v_sal emp.sal%type;

  v_count
binary_integer
;

  v_sum
number
:=0;

begin

  selectcount(rowid)
into v_count
from emp;

  open c_emp_sal;

  for i
in1..v_count
loop

    fetch c_emp_sal
into v_sal;

    v_sum := v_sum+v_sal;

  endloop;

  close c_emp_sal;

  dbms_output.put_line(v_sum);

end;

   

--例子close2:在表emp中,如果职务是CLERK提高工资1%,如果职务是SALESMAN提高工资2%,如果职务是MANAGER提高工资4%

            --如果职务是ANALYST提高工资3%

declare

  cursor c_emp
isselect empno,job
from emp1;

  v_empno emp1.empno%type;

  v_job emp1.job%type;

  v_count
binary_integer
;

begin

  selectcount(rowid)
into v_count
from emp1;

  open c_emp;--开启游标

  for i
in1..v_count
loop--loop开始

    fetch c_emp
into v_empno,v_job;--从游标中取值

    case v_job--case开始

      when'CLERK'then

        update emp1 e
set e.sal=sal*(1+0.1)
where e.empno=v_empno;

        dbms_output.put_line('CLERK OK!');

      when'SALESMAM'then

        update emp1 e
set e.sal=sal*(1+0.2)
where e.empno=v_empno;

        dbms_output.put_line('SALESMAM OK!');

      when'MANAGER'then

        update emp1 e
set e.sal=sal*(1+0.3)
where e.empno=v_empno;

        dbms_output.put_line('MANAGER OK!');

      when'ANALYST'then

        update emp1 e
set e.sal=sal*(1+0.4)
where e.empno=v_empno;

        dbms_output.put_line('ANALYST OK!');

      else

        update emp1 e
set e.sal=sal*(1+0.5)
where e.empno=v_empno;

         dbms_output.put_line('PRESIDENT OK!');

    endcase;--case结束

  endloop;--loop结束

  close c_emp;--关闭游标

end;

 

--例子close3:通过记录存储游标每一条信息

declare

  cursor c_emp
isselect *
from emp;

  v_emp emp%rowtype;

  v_count
binary_integer
;

begin

  selectcount(rowid)
into v_count
from emp;

  open c_emp;

  for i
in1..v_count
loop

    fetch c_emp
into v_emp;

    dbms_output.put_line('salary of emplyee '||v_emp.ename||'
is '
||v_emp.sal);

  endloop;

  close c_emp;

end;

 

--2.2显式游标属性:%found%notfound%isopen%rowcount

--%2.21 %fount是一个布尔属性,如果前一个fetch语句返回一个行,那么它返回true,否则返回false。如果当前游标还没打开引用,则返回错误。

--使用形式:

loop

  fetch c1
into v_ename,v_sal;

  if c1 %foundthen

    ...;

  else

    ...;

    exit;

  endif;

endloop;

 

--2.22 %notfound属性与%found属性相反

loop

  fetch c1
into v_ename,v_sal;

  exitwhen c1 %notfound;

  ...;

endloop;

说明:在第一次提取之前,%notfound属性为null。所以,如果fetch语句没有一次成功执行,那么一直不退出循环。这就是

      为什么当when条件为真时,exit
when
语句才执行。

 

--2.23 %isopen属性,如果游标或游标变量打开,则返回true,否则返回false

if c1 %isopenthen

  ...

  else

    open c1;

endif;

 

--2.24 %rowcount属性,当游标或者游标变量打开时,%rowcount属性置零。

--                   
在第一次提取之前,它的值为0,其后为到该次提取为止所提取的次数。

loop

  fetch c1
into v_ename,v_sal;

  if c1 %rowcount>10then

    ...;

  endif;

endloop;

 

--综合例子1:输出薪金总额(薪水+奖金)高于2000的员工号、员工姓名和工资。

declare

  v_empno emp.empno%type;

  v_ename emp.ename%type;

  v_sal emp.sal%type;

  cursor c_emp
isselect empno, ename, sal
from emp
where sal+nvl(comm,0)>2000;

begin

  open c_emp;

  fetch c_emp
into v_empno, v_ename, v_sal;

  if c_emp%foundthen

    dbms_output.put_line('employees are found with v_sal greater than 2000');

  elsif c_emp%notfoundthen

    dbms_output.put_line('all employee are earning less than or equal to 2000');

  endif;

  if c_emp%isopenthen

    dbms_output.put_line('cursor is already open');

    close c_emp;

  endif;

  open c_emp;

  loop

    fetch c_emp
into v_empno, v_ename, v_sal;

    exitwhen c_emp%notfound;

    dbms_output.put_line(v_empno||','||v_ename||','||v_sal);

  endloop;

  dbms_output.put_line('no of employees are '||c_emp%rowcount);

  close c_emp;

end;

 

--综合例子2:统计每一个部门的工资总额,并按部门显示。

declare

  cursor c_dept
isselect *
from dept
orderby deptno;

  cursor c_emp(p_dept emp.deptno%type)
isselect ename, sal
from emp
where deptno = p_dept
orderby ename;--带参数的游标,可以想象成java中带参数的方法

  r_dept dept%rowtype;

  v_ename emp.ename%type;

  v_salary emp.sal%type;

  v_tot_salary emp.sal%type;--用于存储每一个部门的工资总额

begin

  open c_dept;--打开游标c_dept

  loop

    fetch c_dept
into r_dept;--fetch游标c_dept

    exitwhen c_dept%notfound;

    dbms_output.put_line('##########################department'||r_dept.deptno||'-'||r_dept.dname);

    v_tot_salary:=0;

    open c_emp(r_dept.deptno);--打开游标c_emp

    loop

      fetch c_emp
into v_ename, v_salary;

      exitwhen c_emp%notfound;

      dbms_output.put_line('name'||v_ename||'
salary
'||v_salary);

      v_tot_salary := v_tot_salary+v_salary;

    endloop;

    close c_emp;--关闭游标c_emp

    dbms_output.put_line('##toltal salary for dept'||v_tot_salary);

  endloop;

  close c_dept;--关闭游标c_dept

end;

   

--2.3 cursor for循环:不需要显式打开、关闭和提取数据。很好用的东东~~

--综上所述:

1、打开游标

2、开始循环

3、从游标中取值

4、检查哪一行被返回

5、处理

6、关闭循环

7、关闭游标

 

cursor for的语法:

for record_name
in(cursor_name[parameter[,parameter]...])

loop

  statements

endloop;

 

--cursor for循环的例子1:统计每一个部门的工资总额,并按部门显示。

declare

  cursor c_dept
isselect deptno,dname
from dept
orderby deptno;

  cursor c_emp(p_dept emp.deptno%type)
isselect ename, sal
from emp
where deptno = p_dept
orderby ename;--带参数的游标,可以想象成java中带参数的方法

  v_tot_salary emp.sal%type;--用于存储每一个部门的工资总额

begin

  for r_dept
in c_dept
loop

    dbms_output.put_line('##########################department'||r_dept.deptno||'-'||r_dept.dname);

    v_tot_salary :=
0;

    for r_emp
in c_emp(r_dept.deptno)
loop

      dbms_output.put_line('name'||r_emp.ename||'
salary
'||r_emp.sal);

      v_tot_salary := v_tot_salary+r_emp.sal;

    endloop;

    dbms_output.put_line('##toltal salary

抱歉!评论已关闭.