---游标:一个指向查询结果集的指针,通过这个游标可以获取到结果集中的数据 分为:隐式游标 和 显式游标

---隐式游标:select ... into ... 两个特点: 1、不需要定义,直接使用 2、要求查询结果集只能是一行数据(不能是0行或者多行)

----显式游标 显示游标在使用之前需要定义 --定义/声明显式游标的语法结构: declare cursor 游标名[(参数1 数据类型[,参数2 数据类型,....])] is select 查询结果集; begin --逻辑部分 --使用游标的语法结构 for 循环变量 in 游标名[(实参1[,实参2,....])] loop --循环体,可以 依次(每一次循环) 拿到游标指向的结果集的每一行数据 end loop; end; --开发规范:游标名以 c_ 开头

--需要注意的是: 1、使用前需要声明,可以声明多个游标 2、查询结果集的列名是什么,那么在使用游标的时候就用哪个。使用方式:循环变量名.游标指向的结果集的列名 3、上面的这种用for循环来获取/使用游标中的值的方式,不需要手动管理,直接会从结果集的第一行开始循环,依次得到 结果集的每一行的数据 4、显式游标对结果集没什么要求,可以0行或者1行或者多行

--比如:定义一个游标,输出部门10的员工的工号,姓名 declare cursor c_deptno10 is select empno aaaa,ename from emp where deptno = 10; begin for x in c_deptno10 loop dbms_output.put_line('工号:'||x.aaaa||' 姓名:'||x.ename); end loop; end;

--小练习一把:输出部门20的员工的工号,工资,部门名称,工资等级 declare cursor c_deptno20 is select e.empno, e.sal, d.dname, s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal where e.deptno = 20; begin dbms_output.put_line('工号' || ' 工资' || ' 部门名称' || ' 工资等级'); for x in c_deptno20 loop dbms_output.put_line(x.empno || ' ' || x.sal || ' ' || x.dname || ' ' || x.grade); end loop; end;

---另外一种使用游标的方式:需要手动管理游标:手动打开游标,提取数据,关闭游标 declare --声明游标 begin open 游标名; 游标变量 游标名%rowtype; loop fetch 游标名 Into 游标变量;

** --可以使用游标指向的结果集中的数据了,使用方式:游标变量名.结果集的列名**

** exit when 游标名%notfound;**

** end loop; close 游标名; end;**

--比如:输出部门20的员工的工号,工资,部门名称,工资等级 declare cursor c_deptno20 is select e.empno, e.sal, d.dname, s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal where e.deptno = 20;

v_deptno20 c_deptno20%rowtype; begin dbms_output.put_line('工号' || ' 工资' || ' 部门名称' || ' 工资等级');

open c_deptno20; loop fetch c_deptno20 into v_deptno20;

exit when c_deptno20%notfound;

dbms_output.put_line(v_deptno20.empno || '  ' || v_deptno20.sal ||
                     '    ' || v_deptno20.dname || '  ' ||
                     v_deptno20.grade);

end loop;

close c_deptno20; end;

练习

1 给员工加薪,部门10的加10%,部门20加20%,部门30加30% ,其余的加5%, 编写PLSQL块,打印出各部门员工的姓名,部门编号,工资,加薪后的工资; --方式1:先在结果集中算好,然后用游标指向这个结果集 declare cursor c_newsal is select e.ename, e.deptno, e.sal, case deptno when 10 then sal * 1.1 when 20 then sal * 1.2 when 30 then sal * 1.3 else sal * 1.05 end as new_sal from emp e; begin for x in c_newsal loop dbms_output.put_line('姓名:' || x.ename || ' 部门编号:' || x.deptno || ' 工资:' || x.sal || ' 加薪后的工资:' || x.new_sal); end loop; end;

--方式2:在循环里面做判断 declare cursor c_deptno is select e.sal, e.deptno, e.ename from emp e; v_newsal emp.sal%type; begin for x in c_deptno loop if x.deptno = 10 then v_newsal := x.sal * 1.1; elsif x.deptno = 20 then v_newsal := x.sal * 1.2; elsif x.deptno = 30 then v_newsal := x.sal * 1.3; else v_newsal := x.sal * 1.05; end if; dbms_output.put_line('姓名:' || x.ename || ' 部门编号:' || x.deptno || ' 工资:' || x.sal || ' 加薪后的工资:' || v_newsal); end loop; end;

2 打印出各个部门的员工的姓名(包括部门编号为40),打印结果为: 部门10的员工: AAA ... 部门20的员工: XXX ... 部门30的员工: XXX ... 部门40的员工:

declare cursor c_dept is select deptno from dept;

cursor c_emp is select deptno, ename from emp;

begin for x in c_dept loop dbms_output.put_line('部门' || x.deptno || '的员工:'); for y in c_emp loop if y.deptno = x.deptno then dbms_output.put_line(' ' || y.ename); end if; end loop; end loop; end;

3 编写一个PL/SQL程序块,从emp表中对名字以"A"或"S"开始的所有雇员按他们基本薪水的10%给他们加薪,打印出员工的姓名,薪水,加薪后的薪水。 declare cursor c_sal is select e.*, e.sal * 1.1 as new_sal from emp e where /ename like 'A%' or ename like 'S%'/ substr(ename, 1, 1) in ('A', 'S'); begin DBMS_OUTPUT.PUT_LINE('姓名 ' || '薪水 ' || '加薪后的薪水'); FOR X IN c_sal LOOP DBMS_OUTPUT.PUT_LINE(X.ENAME || ' ' || X.SAL || ' ' || x.new_sal); end loop; end;


DECLARE CURSOR C_EMP IS select E.ENAME, E.SAL from emp e where e.eNAME like 'A%' OR E.ENAME LIKE 'S%' ORDER BY E.ENAME; V_NEWSAL EMP.SAL%TYPE; BEGIN DBMS_OUTPUT.PUT_LINE('姓名 ' || '薪水 ' || '加薪后的薪水'); FOR X IN C_EMP LOOP V_NEWSAL := X.SAL * 1.1; DBMS_OUTPUT.PUT_LINE(X.ENAME || ' ' || X.SAL || ' ' || V_NEWSAL); end loop; END;

4 按员工的入职日期,打印出 员工的姓名,入职时间,季度的第一天,季度的最后一天,当年的第一天,当年的最后一天 declare cursor c_hire is select e.*, trunc(e.hiredate, 'q') first_q, trunc(add_months(e.hiredate, 3), 'q') - 1 last_q, trunc(e.hiredate, 'yyyy') first_y, trunc(add_months(e.hiredate, 12), 'yyyy') - 1 last_y from emp e;

begin for x in c_hire loop dbms_output.put_line(x.ename || ' ' || to_char(x.hiredate, 'yyyy-mm-dd') || ' ' || to_char(x.first_q, 'yyyy-mm-dd') || ' ' || to_char(x.last_q, 'yyyy-mm-dd') || ' ' || to_char(x.first_y, 'yyyy-mm-dd') || ' ' || to_char(x.last_y, 'yyyy-mm-dd')); end loop; end;