v_error_code := SQLCODE ;
v_error_message := SQLERRM ; INSERT INTO errors
VALUES(v_error_code, v_error_message); END;
【练习1】修改雇员的工资,通过引发异常控制修改范围在600~6000之间。 阶段训练
【训练1】 将雇员从一个表复制到另一个表。 步骤1:创建一个结构同EMP表一样的新表EMP1:
CREATE TABLE emp1 AS SELECT * FROM SCOTT.EMP WHERE 1=2; 步骤2:通过指定雇员编号,将雇员由EMP表移动到EMP1表: Sql代码
1. SET SERVEROUTPUT ON 2. DECLARE
3. v_empno NUMBER(5):=7788; 4. emp_rec emp%ROWTYPE; 5. BEGIN
6. SELECT * INTO emp_rec FROM emp WHERE empno=v_empno; 7. DELETE FROM emp WHERE empno=v_empno; 8. INSERT INTO emp1 VALUES emp_rec; 9. IF SQL%FOUND THEN 10. COMMIT;
11. DBMS_OUTPUT.PUT_LINE('雇员复制成功!'); 12. ELSE
13. ROLLBACK;
14. DBMS_OUTPUT.PUT_LINE('雇员复制失败!'); 15. END IF; 16. END;
执行结果为: 雇员复制成功!
PL/SQL 过程已成功完成。
步骤2:显示复制结果:
SELECT empno,ename,job FROM emp1; 执行结果为: Sql代码
1. EMPNO ENAME JOB
2. ------------- -------------- ---------------- 3. 7788 SCOTT ANALYST
说明:emp_rec变量是根据emp表定义的记录变量,SELECT...INTO...语句将整个记录传给该变量。INSERT语句将整个记录变量插入emp1表,如果插入成功(SQL%FOUND为真),则提交事务,否则回滚撤销事务。试修改雇员编号为7902,重新执行以上程序。 【训练2】 输出雇员工资,雇员工资用不同高度的*表示。 输入并执行以下程序: Sql代码
1. SET SERVEROUTPUT ON 2. BEGIN
3. FOR re IN (SELECT ename,sal FROM EMP) LOOP
4. DBMS_OUTPUT.PUT_LINE(rpad(re.ename,12,' ')||rpad('*',re.sal/100,'*'));
5. END LOOP; 6. END;
输出结果为: Sql代码
1. SMITH ********
2. ALLEN **************** 3. WARD *************
4. JONES ****************************** 5. MARTIN *************
6. BLAKE *****************************
7. CLARK *****************************
8. SCOTT ******************************
9. KING ************************************************** 10. TURNER *************** 11. ADAMS *********** 12. JAMES **********
13. FORD ****************************** 14. MILLER ************* 15. 执行结果为:
16. PL/SQL 过程已成功完成。
说明:第一个rpad函数产生对齐效果,第二个rpad函数根据工资额产生不同数目的*。该程序采用了隐式的简略游标循环形式。
【训练3】 编写程序,格式化输出部门信息。 输入并执行如下程序: Sql代码:
1. SET SERVEROUTPUT ON
2. DECLARE 3. 4. 5. 6.
v_count number:=0;
CURSOR dept_cursor IS SELECT * FROM dept; BEGIN
DBMS_OUTPUT.PUT_LINE('部门列表');
7. DBMS_OUTPUT.PUT_LINE('---------------------------------'); 8. FOR Dept_record IN dept_cursor LOOP
9. DBMS_OUTPUT.PUT_LINE('部门编号:'|| Dept_record.deptno); 10. DBMS_OUTPUT.PUT_LINE('部门名称:'|| Dept_record.dname); 11. DBMS_OUTPUT.PUT_LINE('所在城市:'|| Dept_record.loc); 12. DBMS_OUTPUT.PUT_LINE('---------------------------------'); 13. v_count:= v_count+1;
14. END LOOP;
15. DBMS_OUTPUT.PUT_LINE('共有'||to_char(v_count)||'个部门!'); 16. END;
输出结果为: Sql代码
1. 部门列表
2. ------------------------------------ 3. 部门编号:10
4. 部门名称:ACCOUNTING 5. 所在城市:NEW YORK 6. 7. 8. 9.
------------------------------------ 部门编号:20
部门名称:RESEARCH 所在城市:DALLAS
10. ...
11. 共有4个部门!
12. PL/SQL 过程已成功完成。
说明:该程序中将字段内容垂直排列。V_count变量记录循环次数,即部门个数。 【训练4】 已知每个部门有一个经理,编写程序,统计输出部门名称、部门总人数、总工资和部门经理。
输入并执行如下程序: Sql代码
1. SET SERVEROUTPUT ON 2. DECLARE
3. v_deptno number(8); 4. v_count number(3); 5. v_sumsal number(6);
6. v_dname varchar2(15);
7. v_manager varchar2(15); 8. CURSOR list_cursor IS
9. SELECT deptno,count(*),sum(sal) FROM emp group by deptno; 10. BEGIN
11. OPEN list_cursor;
12. DBMS_OUTPUT.PUT_LINE('----------- 部 门 统 计 表 -----------'); 13. DBMS_OUTPUT.PUT_LINE('部门名称 总人数 总工资 部门经理'); 14. FETCH list_cursor INTO v_deptno,v_count,v_sumsal; 15. WHILE list_cursor%found LOOP 16. SELECT dname INTO v_dname FROM dept 17. WHERE deptno=v_deptno;
18. SELECT ename INTO v_manager FROM emp 19. WHERE deptno=v_deptno and job='MANAGER';
20. DBMS_OUTPUT.PUT_LINE(rpad(v_dname,13)||rpad(to_char(v_count),8) 21. ||rpad(to_char(v_sumsal),9)||v_manager);
22. FETCH list_cursor INTO v_deptno,v_count,v_sumsal; 23. END LOOP;
24. DBMS_OUTPUT.PUT_LINE('--------------------------------------');
25. CLOSE list_cursor; 26. END;
输出结果为: Sql代码
1. -------------------- 部 门 统 计 表 ----------------- 2. 部门名称 总人数 总工资 部门经理 3. ACCOUNTING 3 8750 CLARK 4. 5. 6. 7.
RESEARCH 5 10875 JONES
SALES 6 9400 BLAKE
------------------------------------------------------------- PL/SQL 过程已成功完成。
说明:游标中使用到了起分组功能的SELECT语句,统计出各部门的总人数和总工资。再根据部门编号和职务找到部门的经理。该程序假定每个部门有一个经理。
【训练5】 为雇员增加工资,从工资低的雇员开始,为每个人增加原工资的10%,限定所增加的工资总额为800元,显示增加工资的人数和余额。 输入并调试以下程序: Sql代码
1. SET SERVEROUTPUT ON 2. DECLARE
3. V_NAME CHAR(10); 4. 5. 6. 7.
V_EMPNO NUMBER(5); V_SAL NUMBER(8); V_SAL1 NUMBER(8);
V_TOTAL NUMBER(8) := 800; --增加工资的总额
8. V_NUM NUMBER(5):=0; --增加工资的人数 9. CURSOR emp_cursor IS
10. SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL ASC; 11. BEGIN
12. OPEN emp_cursor;
13. DBMS_OUTPUT.PUT_LINE('姓名 原工资 新工资'); 14. DBMS_OUTPUT.PUT_LINE('---------------------------'); 15. LOOP
16. FETCH emp_cursor INTO V_EMPNO,V_NAME,V_SAL; 17. EXIT WHEN emp_cursor%NOTFOUND; 18. V_SAL1:= V_SAL*0.1;
19. IF V_TOTAL>V_SAL1 THEN
20. V_TOTAL := V_TOTAL - V_SAL1; 21. V_NUM:=V_NUM+1;
22. DBMS_OUTPUT.PUT_LINE(V_NAME||TO_CHAR(V_SAL,'99999')|| 23. TO_CHAR(V_SAL+V_SAL1,'99999'));
24. UPDATE EMP SET SAL=SAL+V_SAL1 25. WHERE EMPNO=V_EMPNO; 26. ELSE
27. DBMS_OUTPUT.PUT_LINE(V_NAME||TO_CHAR(V_SAL,'99999')||TO_CHAR(V_SAL,'99999'));
28. END IF;
29. END LOOP;
30. DBMS_OUTPUT.PUT_LINE('---------------------------'); 31. DBMS_OUTPUT.PUT_LINE('增加工资人数:'||V_NUM||' 剩余工资:'||V_TOTAL);
32. CLOSE emp_cursor; 33. COMMIT; 34. END;
输出结果为: Sql代码
1. 姓名 原工资 新工资
2. --------------------------------------------- 3. SMITH 1289 1418 4. JAMES 1531 1684 5. MARTIN 1664 1830
6. MILLER 1730 1903