游标的出现是为了解决从某一结果集中逐一读取一条记录。
--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