CURSOR c1 IS
SELECT sal FROM emp; sum_xx number; BEGIN
sum_xx:=0;
FOR r1 IN c1 LOOP
IF r1.sal>0 and r1.sal<=2000 THEN sum_xx:=sum_xx;
ELSIF r1.sal >2000 and r1.sal<=3000 THEN sum_xx:=sum_xx+(r1.sal-2000)*0.1;
ELSIF r1.sal>3000 and r1.sal<=4000 THEN sum_xx:=sum_xx+(r1.sal-3000)*0.2;
ELSIF r1.sal>4000 and r1.sal<=5000 THEN sum_xx:=sum_xx+(r1.sal-4000)*0.3; ELSE
sum_xx:=sum_xx+(r1.sal-5000)*0.4; END IF; END LOOP;
dbms_output.put_line('所有雇员的所得税总和:'||sum_xx); END; /
给出运行测试结果:
7. 创建一个PL/SQL块,声明一个游标,从emp表中选择姓名,薪水和雇佣日期。从游标
检索每一行,如果雇员的薪水大于50000元,而且雇佣日期在1997年12月31日之前,则显示雇员的具体信息。 写出程序源码:
Declare
Cursor mycursor is
Select ename,sal,hiredate from emp; Begin
dbms_output.put_line('薪水大于4000元,且雇佣日期在1997-12-31之前
第 26 页 共 31 页
雇员的信息:');
for r in mycursor loop
if r.sal>4000 and r.hiredate<'31-12月-97'then dbms_output.put_line(r.ename); dbms_output.put_line(r.sal);
dbms_output.put_line(r.hiredate); end if; end loop; end;
给出运行测试结果:
8. 创建一个PL/SQL块,声明一个游标。将与emp数据表中sal相同类型的一个参数传递
给此游标。用此参数打开上述的游标。将薪水值大于此参数(如3000)的雇员和有关信息检索到该游标中,并且显示这些雇员的具体信息。 写出程序源码:
Declare
Type c1 is ref cursor; v_c1 c1;
mer_rec emp%rowtype; Begin
dbms_output.put_line('查询薪水值不小于5000的雇员信息'); open v_c1 for select * from emp where sal>=5000; Loop
Fetch v_c1 into mer_rec; Exit when v_c1%notfound;
dbms_output.put_line(mer_rec.empno||' ' ||mer_rec.ename||'
'||mer_rec.job||' '||mer_rec.mgr||' '||mer_rec.hiredate||' '||mer_rec.sal||' '||mer_rec.comm||' '||mer_rec.deptno);
End loop;
第 27 页 共 31 页
Close v_c1; End;
给出运行测试结果:
9. 创建一个PL/SQL块,为部门10的用户加薪。薪水低于1000美元的雇员加薪15%,薪
水等于或高于1000美元的雇员加薪10%。使用含for update子句的游标,以及通过for 循环的where current of子句实现加薪处理。(要求测试结果中给出测试前表中相关值和程序执行完成后表中数据相关值,以便比对验证) 写出程序源码:
Declare
Cursor addsal_cursor is Select * from emp Where deptno='10'
For update of sal nowait; v_sal number(7,2); Begin
For r in addsal_cursor loop If r.sal<1000 then v_sal:=r.sal*0.15; Else
v_sal:=r.sal*0.1; end if; update emp
set sal=sal+v_sal
where current of addsal_cursor; End loop; End;
给出运行测试结果:
第 28 页 共 31 页
10. 编写一个PL/SQL块,要求用户输入第一个数字、第二个数字和算术运算符(+、-、
*、/)。如果运算符无效,则抛出一个用户自定义异常,如果第二个数字是零而且运算符是/,则处理ZERO_DIVIDE预定义的服务器异常。 写出程序源码:
set serveroutput on declare
ex_char exception; fnum number(4); snum number(4); ch varchar2(4); result number(6); begin
fnum:=&操作数1; ch:='&符号'; snum:=&操作数2;
if ch='+' then result:=fnum+snum; elsif ch='-' then result:=fnum-snum; elsif ch='*' then result:=fnum*snum; elsif ch='/' then result:=fnum/snum; else raise ex_char; end if;
dbms_output.put_line('结果='||result); exception
when zero_divide then dbms_output.put_line('除数不能为0'); when value_error then dbms_output.put_line('操作数有误'); when ex_char then dbms_output.put_line('只能输入+.-.*./'); End;
给出运行测试结果:
第 29 页 共 31 页
11. 编写一个PL/SQL程序块,对名字以\或\开始的所有雇员按他们的基本薪水的
10%加薪。
写出程序源码:
DECLARE
CURSOR C1 IS
SELECT * FROM emp
WHERE SUBSTR(ename,1,1)='S' FOR UPDATE OF sal; BEGIN
FOR i IN c1 LOOP
UPDATE emp SET sal=NVL(sal,0)+NVL(sal,0)*0.1 WHERE CURRENT OF c1; END LOOP; END;
给出运行测试结果:
第 30 页 共 31 页
附:常见预定义的异常处理
预定义说明的部分 ORACLE 异常错误 错误号 ORA-0001 ORA-0051 ORA-0061 ORA-1001 ORA-1012 ORA-1017 ORA-1403 ORA-1422 ORA-1476 ORA-1722 ORA-6500 ORA-6501 ORA-6502 ORA-6504 ORA-6511 ORA-6530 ORA-6531 ORA-6532 ORA-6533 异常错误信息名称 Dup_val_on_index Timeout-on-resource Transaction-backed-out Invalid-CURSOR Not-logged-on Login-denied No_data_found Too_many_rows Zero-divide Invalid-NUMBER Storage-error Program-error Value-error Rowtype-mismatch CURSOR-already-OPEN Access-INTO-null Collection-is-null Subscript-outside-limit Subscript-beyond-count 说明 试图破坏一个唯一性限制 在等待资源时发生超时 由于发生死锁事务被撤消 试图使用一个无效的游标 没有连接到ORACLE 无效的用户名/口令 SELECT INTO没有找到数据 SELECT INTO 返回多行 试图被零除 转换一个数字失败 内存不够引发的内部错误 内部错误 转换或截断错误 缩主游标变量与 PL/SQL变量有不兼容行类型 试图打开一个已存在的游标 试图为null 对象的属性赋值 试图将Exists 以外的集合( collection)方法应用于一个null pl/sql 表上或varray上 对嵌套或varray索引得引用超出声明范围以外 对嵌套或varray 索引得引用大于集合中元素的个数. 第 31 页 共 31 页