源码-Oracle数据库管理-第十三章-子程序和包-Part 4(定义PL/SQL包)

来源:互联网 发布:英雄无敌 mac 10.13 编辑:程序博客网 时间:2024/05/29 17:22

业精于勤荒于嬉,行成于思毁于随!切记切记!奋斗


--代码13.12 包规范定义示例--定义包规范,包规范将被用于应用程序的接口部分,供外部调用CREATE OR REPLACE PACKAGE emp_pkg AS   --定义集合类型   TYPE emp_tab IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;   --在包规范中定义一个记录类型   TYPE emprectyp IS RECORD(      emp_no NUMBER,      sal  NUMBER   );   --定义一个游标声明   CURSOR desc_salary RETURN emprectyp;   --定义雇佣员工的过程   PROCEDURE hire_employee(p_empno NUMBER,p_ename VARCHAR2,p_job VARCHAR2,p_mgr NUMBER,p_sal NUMBER,                        p_comm NUMBER,p_deptno NUMBER);   --定义解雇员工的过程                           PROCEDURE fire_employee(p_emp_id NUMBER );END emp_pkg;--代码13.13 包体定义示例--定义包体CREATE OR REPLACE PACKAGE BODY emp_pkgAS   --定义游标声明的游标体   CURSOR desc_salary RETURN emprectyp IS      SELECT   empno, sal FROM emp ORDER BY sal DESC;   --定义雇佣员工的具体实现   PROCEDURE hire_employee(p_empno NUMBER,p_ename VARCHAR2,                           p_job VARCHAR2,p_mgr NUMBER,p_sal NUMBER,                           p_comm NUMBER,p_deptno NUMBER) IS   BEGIN      --向emp表中插入一条员工信息      INSERT INTO emp VALUES(p_empno,p_ename,p_job,p_mgr,SYSDATE,p_sal,p_comm,p_deptno);    END;          --定义解雇员工的具体实现                    PROCEDURE fire_employee(p_emp_id NUMBER ) IS   BEGIN      --从emp表中删除员工信息      DELETE FROM emp WHERE empno=p_emp_id;   END;          END emp_pkg;--代码13.14 引用包中的游标DECLARE   v_desc_sal_row emp_pkg.emprectyp;               --定义游标返回类型变量BEGIN  OPEN emp_pkg.desc_salary;                        --打开在包中定义的游标  LOOP     FETCH emp_pkg.desc_salary INTO v_desc_sal_row;--提取游标数据     --输出员工信息     DBMS_OUTPUT.put_line('员工工号:'||v_desc_sal_row.emp_no                         ||' 员工工资:'||v_desc_sal_row.sal);              EXIT WHEN emp_pkg.desc_salary%NOTFOUND;       --提取完成退出游标  END LOOP;  CLOSE emp_pkg.desc_salary;                       --关闭游标END;--13.3.2 定义包规范--代码13.15 定义人事信息管理包规范CREATE OR REPLACE PACKAGE emp_mgmt_pkg AS  --添加新员工,返回新增员工的工号  FUNCTION hire(p_ename         VARCHAR2,                p_job         VARCHAR2,                p_mgr       NUMBER,                p_sal         NUMBER,                p_comm      NUMBER,                p_deptno  NUMBER) RETURN NUMBER;  --创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER, p_loc VARCHAR2)    RETURN NUMBER;  --移除一个员工  PROCEDURE remove_emp(p_empno NUMBER);  --移除一个部门  PROCEDURE remove_dept(p_deptno NUMBER);  --增加员工工资  PROCEDURE increase_sal(p_empno NUMBER, p_sal_incr NUMBER);  --增加员工的提成  PROCEDURE increase_comm(p_empno NUMBER, p_comm_incr NUMBER);  no_comm EXCEPTION;           --没有提成数量的异常  no_sal EXCEPTION;            --没有工资数量的异常END emp_mgmt_pkg;/DECLARE   v_comm NUMBER:=&comm;          --定义一个替换变量,要求用户输入一个值BEGIN  IF v_comm<=0 THEN              --如果输入的值小于或等于0    RAISE emp_mgmt_pkg.no_comm;  --抛出在包中定义的异常  END IF;EXCEPTION   WHEN emp_mgmt_pkg.no_comm THEN --在异常处理部分捕捉并处理该异常     DBMS_OUTPUT.put_line('没有指定员工提成!');END;--13.3.3 定义包体--代码13.16 实现人事信息管理包体CREATE OR REPLACE PACKAGE BODY emp_mgmt_pkg AS   tot_emps NUMBER;        --总员工数量   tot_depts NUMBER;       --总的部门数量  --添加新员工,返回新增员工的工号  FUNCTION hire(p_ename         VARCHAR2,                p_job         VARCHAR2,                p_mgr       NUMBER,                p_sal         NUMBER,                p_comm      NUMBER,                p_deptno  NUMBER) RETURN NUMBER AS   v_empno  NUMBER; BEGIN   v_empno:=8350;   INSERT INTO emp VALUES(v_empno,p_ename,p_job,p_mgr,SYSDATE,p_sal,p_comm,p_deptno);   tot_emps := tot_emps + 1;    RETURN v_empno;     END hire;   --创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER, p_loc VARCHAR2)    RETURN NUMBER  IS  BEGIN    INSERT INTO dept VALUES(p_deptno,'其他部门',p_loc);    tot_depts := tot_depts + 1;         RETURN p_deptno;      END create_dept;       --移除一个员工  PROCEDURE remove_emp(p_empno NUMBER)  IS  BEGIN      DELETE FROM emp       WHERE emp.empno = p_empno;       tot_emps := tot_emps - 1;     END remove_emp;    --移除一个部门  PROCEDURE remove_dept(p_deptno NUMBER)   IS  BEGIN      DELETE FROM dept       WHERE dept.deptno = p_deptno;       tot_depts := tot_depts - 1;       SELECT COUNT(*) INTO tot_emps FROM emp;       END remove_dept;    --增加员工工资  PROCEDURE increase_sal(p_empno NUMBER, p_sal_incr NUMBER)  IS   curr_sal NUMBER;    BEGIN       SELECT sal INTO curr_sal FROM emp       WHERE emp.empno= p_empno;       IF curr_sal IS NULL THEN           RAISE no_sal;       ELSE          UPDATE emp          SET sal = sal + p_sal_incr          WHERE empno = p_empno;       END IF;      END increase_sal;     --增加员工的提成  PROCEDURE increase_comm(p_empno NUMBER, p_comm_incr NUMBER)  IS   curr_comm NUMBER;    BEGIN       SELECT comm       INTO curr_comm       FROM emp       WHERE emp.empno = p_empno;       IF curr_comm IS NULL THEN           RAISE no_comm;       ELSE          UPDATE emp          SET comm = comm + p_comm_incr         WHERE emp.empno=p_empno;      END IF;    END increase_comm; BEGIN            --包初始化部分   SELECT COUNT(*) INTO tot_emps FROM emp;        SELECT COUNT(*) INTO tot_depts FROM dept;           END emp_mgmt_pkg;--13.3.4 子程序重载--代码13.17 重载方法包规范示例CREATE OR REPLACE PACKAGE emp_mgmt_pkg_overloading AS  --重载函数,添加新员工,返回新增员工的工号  FUNCTION hire(p_ename         VARCHAR2,                p_job         VARCHAR2,                p_mgr       NUMBER,                p_sal         NUMBER,                p_comm      NUMBER,                p_deptno  NUMBER) RETURN NUMBER;                  --重载函数,添加新员工,返回新增员工的工号  FUNCTION hire(p_empno       NUMBER,                p_job         VARCHAR2,                p_deptno  NUMBER) RETURN NUMBER;                                  --重载函数,创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER, p_loc VARCHAR2)    RETURN NUMBER;      --重载函数,创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER,p_dname VARCHAR2,p_loc VARCHAR2)    RETURN NUMBER;     END emp_mgmt_pkg_overloading;--非法的重载方法,只是名称和模式的不同不能进行重载  FUNCTION create_dept(p_deptno IN NUMBER, p_loc IN VARCHAR2) RETURN NUMBER;  FUNCTION create_dept(deptno IN NUMBER, loc IN OUT VARCHAR2) RETURN NUMBER;    --非法的重载方法,函数的返回类型不同的不能进行重载  FUNCTION create_dept(p_deptno IN NUMBER, p_loc IN VARCHAR2) RETURN NUMBER;    FUNCTION create_dept(p_deptno IN NUMBER, p_loc IN VARCHAR2) RETURN VARCHAR2;      --非法的重载方法,不能对相同类型系统的参数进行重载  FUNCTION create_dept(p_deptno IN NUMBER, p_loc IN VARCHAR2) RETURN NUMBER;    FUNCTION create_dept(p_deptno IN NUMBER, p_loc IN CHAR) RETURN VARCHAR2;     --13.3.5 调用包组件--代码13.18 重载方法包体示例CREATE OR REPLACE PACKAGE BODY emp_mgmt_pkg_overloading AS  --重载函数,添加新员工,返回新增员工的工号  FUNCTION hire(p_ename         VARCHAR2,                p_job         VARCHAR2,                p_mgr       NUMBER,                p_sal         NUMBER,                p_comm      NUMBER,                p_deptno  NUMBER) RETURN NUMBER AS   v_empno  NUMBER;  BEGIN     v_empno:=8350;     INSERT INTO emp VALUES(v_empno,p_ename,p_job,p_mgr,SYSDATE,p_sal,p_comm,p_deptno);     RETURN v_empno;         END;                  --重载函数,添加新员工,返回新增员工的工号  FUNCTION hire(p_empno       NUMBER,                p_job         VARCHAR2,                p_deptno  NUMBER) RETURN NUMBER  AS  BEGIN          INSERT INTO emp(empno,job,deptno) VALUES(p_empno,p_job,p_deptno);     RETURN p_empno;      END;                                                 --重载函数,创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER, p_loc VARCHAR2)    RETURN NUMBER  AS  BEGIN    INSERT INTO dept VALUES(p_deptno,'其他部门',p_loc);         RETURN p_deptno;       END;      --重载函数,创建新部门,返回新增部门的部门编号  FUNCTION create_dept(p_deptno NUMBER,p_dname VARCHAR2,p_loc VARCHAR2)    RETURN NUMBER  AS  BEGIN    INSERT INTO dept VALUES(p_deptno,p_dname,p_loc);    RETURN p_deptno;       END;   END emp_mgmt_pkg_overloading;select * from emp where ename='李三';BEGIN  --重载方法使用示例,增加薪员工  emp_mgmt_pkg_overloading.hire('李三','分析员',NULL,3000,500,20);  emp_mgmt_pkg_overloading.hire(8351,'销售员',20);      --重载方法使用示例,创建新部门  emp_mgmt_pkg_overloading.create_dept(90,'南宁');  emp_mgmt_pkg_overloading.create_dept(91,'行政部','天津');      END;--13.3.5 调用包组件--代码13.19 有状态的包创建示例    --创建有状态的包规范,获取员工信息CREATE OR REPLACE PACKAGE stateful_emp_pkg AS  --保存员工名称的索引表变量  TYPE t_emptable IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;  --获取最大行数  v_MaxRows NUMBER := 5;  --读取员工名称到索引表中  PROCEDURE ReadEmp(p_emptable OUT t_emptable, p_NumRows OUT NUMBER);END stateful_emp_pkg;--创建有状态的包体,获取员工信息CREATE OR REPLACE PACKAGE BODY stateful_emp_pkg AS  --定义包体游标,用来从emp表中查询员工数据  CURSOR c_empname IS    SELECT ename FROM emp WHERE deptno = 20 ORDER BY empno;  --实现包规范中的子程序,获取员工名称到索引表中  PROCEDURE ReadEmp(p_emptable OUT t_emptable, p_NumRows OUT NUMBER)  AS    v_Done    BOOLEAN := FALSE;          --是否游标财用完成    v_NumRows NUMBER := 1;               --起始下标值  BEGIN    DBMS_OUTPUT.put_line('正在打开游标');    IF NOT c_empname%ISOPEN THEN         --判断游标是否打开,未打开则调用OPEN语句      OPEN c_empname;      DBMS_OUTPUT.put_line('已经打开游标');          END IF;     WHILE NOT v_Done LOOP                --判断游标是否提取结束,如果还有数据则继续提取      FETCH c_empname        INTO p_emptable(v_NumRows);      --将游标数据保存到索引表中      IF c_empname%NOTFOUND THEN         --如果游标提取完成         CLOSE c_empname;        v_Done := TRUE;                  --关闭游标,并设置布尔变量      ELSE        v_NumRows := v_NumRows + 1;      --下标值加1        IF v_NumRows > v_MaxRows THEN    --只提取v_MaxRows变量指定的行数          v_Done := TRUE;        END IF;      END IF;    END LOOP;    p_NumRows := v_NumRows - 1;          --返回已经提取的行数  END ReadEmp;END stateful_emp_pkg;--代码13.20 状态包调用示例--匿名块的调用代码DECLARE  v_emp_tbl stateful_emp_pkg.t_emptable;            --定义索引表变量  v_numrows   NUMBER ;                              --获取已提取的行数  v_ename     emp.ename%TYPE;  --定义一个嵌套子程序,用来输出信息  PROCEDURE read_emp AS  BEGIN    stateful_emp_pkg.ReadEmp(v_emp_tbl, v_numrows); --调用包中的方法读取emp表中的数据    DBMS_OUTPUT.PUT_LINE(' 已经提取了 ' || v_numrows || ' 行:');      FOR v_Count IN 1 .. v_NumRows LOOP              --输出索引表中的员工名称      DBMS_OUTPUT.PUT_LINE(v_emp_tbl(v_Count));    END LOOP;      END;  BEGIN  --显示当前的记录行数  DBMS_OUTPUT.put_line('当前v_MaxRows的值为:'||stateful_emp_pkg.v_MaxRows);  read_emp;                                        --调用嵌套的子程序调用包组件  stateful_emp_pkg.v_MaxRows:=3;                   --重新设置最大行数  DBMS_OUTPUT.put_line('当前v_MaxRows的值为:'||stateful_emp_pkg.v_MaxRows);    read_emp;  END;--代码13.21 可串行化复用包定义示例--创建有状态的包规范,获取员工信息CREATE OR REPLACE PACKAGE stateful_emp_pkg AS  PRAGMA SERIALLY_REUSABLE;  --保存员工名称的索引表变量  TYPE t_emptable IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;  --获取最大行数  v_MaxRows NUMBER := 5;  --读取员工名称到索引表中  PROCEDURE ReadEmp(p_emptable OUT t_emptable, p_NumRows OUT NUMBER);END stateful_emp_pkg;--创建有状态的包体,获取员工信息CREATE OR REPLACE PACKAGE BODY stateful_emp_pkg AS  PRAGMA SERIALLY_REUSABLE;  --定义包体游标,用来从emp表中查询员工数据  CURSOR c_empname IS    SELECT ename FROM emp WHERE deptno = 20 ORDER BY empno;  --实现包规范中的子程序,获取员工名称到索引表中  PROCEDURE ReadEmp(p_emptable OUT t_emptable, p_NumRows OUT NUMBER)  AS    v_Done    BOOLEAN := FALSE;          --是否游标财用完成    v_NumRows NUMBER := 1;               --起始下标值  BEGIN    DBMS_OUTPUT.put_line('正在打开游标');    IF NOT c_empname%ISOPEN THEN         --判断游标是否打开,未打开则调用OPEN语句      OPEN c_empname;      DBMS_OUTPUT.put_line('已经打开游标');          END IF;     WHILE NOT v_Done LOOP                --判断游标是否提取结束,如果还有数据则继续提取      FETCH c_empname        INTO p_emptable(v_NumRows);      --将游标数据保存到索引表中      IF c_empname%NOTFOUND THEN         --如果游标提取完成         CLOSE c_empname;        v_Done := TRUE;                  --关闭游标,并设置布尔变量      ELSE        v_NumRows := v_NumRows + 1;      --下标值加1        IF v_NumRows > v_MaxRows THEN    --只提取v_MaxRows变量指定的行数          v_Done := TRUE;        END IF;      END IF;    END LOOP;    p_NumRows := v_NumRows - 1;          --返回已经提取的行数  END ReadEmp;END stateful_emp_pkg;--13.3.6 重新编译包--编译包规范scott_Ding@ORCL> ALTER PACKAGE stateful_emp_pkg COMPILE SPECIFICATION;Package altered.--编译包体scott_Ding@ORCL> ALTER PACKAGE stateful_emp_pkg COMPILE BODY;  Package body altered.--同时编译包规范和包体scott_Ding@ORCL> ALTER PACKAGE stateful_emp_pkg COMPILE PACKAGE;Package altered.--13.3.7 查看包的源代码select object_name, object_type, created, last_ddl_time from user_objects where object_type in ('PACKAGE','PACKAGE BODY');SELECT line, text FROM user_source WHERE name ='EMP_PKG' AND type='PACKAGE';

0 0
原创粉丝点击