源码-PL/SQL从入门到精通-第十四章-包-Part 1
来源:互联网 发布:日落黄沙知乎 编辑:程序博客网 时间:2024/05/21 09:10
调试经验:
1. 编译包时,如果出现编译错误(PL/SQL developer中包名出现红叉),可通过以下语句查看:
SELECT name,line, POSITION, text
FROM user_errors
WHERE NAME = 'INITTEST'
ORDER BY SEQUENCE;
2. 上述语句中,引号中的包名(如,INITTEST)一定要大写,否则查不到
另外,PL/SQL中的包分为包规范(包的定义)和包体(包的实现)两部分,是PL/SQL编程的基本单元。
虽然名称为包,但包中内容无非是一些类型定义(常量、集合、记录、游标、函数、过程等变量)及实现方法,这更像是Java中的一个类(字段+方法),而比Java的包(package) 又低一个层次。
--第14章开始--代码14.1 包规范定义示例--定义包规范,包规范将被用于应用程序的接口部分,供外部调用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,p_hiredate DATE); --定义解雇员工的过程 PROCEDURE fire_employee(p_emp_id NUMBER );END emp_pkg;--代码14.2 包体定义示例--定义包体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,p_hiredate DATE) IS BEGIN --向emp表中插入一条员工信息 INSERT INTO emp VALUES(p_empno,p_ename,p_job,p_mgr,p_hiredate,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;--代码14.3 包规范定义示例--定义包规范,包规范将被用于应用程序的接口部分,供外部调用CREATE OR REPLACE PACKAGE dept_pkg AS dept_count NUMBER:=1; --定义集合类型 TYPE dept_tab IS TABLE OF dept%ROWTYPE INDEX BY BINARY_INTEGER; --在包规范中定义一个记录类型 TYPE deptrectyp IS RECORD( dept_no NUMBER, dname VARCHAR2(30), loc VARCHAR2(30) ); CURSOR deptcur RETURN deptrectyp; --定义一个游标变量 e_nodept_assign EXCEPTION; --定义一个异常END dept_pkg;--代码14.4 调用包规范中定义的元素DECLARE mydept dept_pkg.dept_tab; --定义包中的集合类型的变量 BEGIN FOR deptrow IN (SELECT * FROM dept) LOOP --使用游标FOR循环提取dept数据 mydept(dept_pkg.dept_count):=deptrow; --为集合类型赋值 dept_pkg.dept_count:=dept_pkg.dept_count+1; --递增包中的变量的值 END LOOP; FOR i IN 1..mydept.count LOOP --循环显示集合中的部门的部门名称 DBMS_OUTPUT.put_line(mydept(i).dname); END LOOP; dept_pkg.dept_count:=1; --重置dept_pkg.dept_count的值。EXCEPTION WHEN dept_pkg.e_nodept_assign THEN DBMS_OUTPUT.put_line('没有找到员工记录'); --捕捉异常,如果有触发的话END; --代码14.5 包体实现示例--定义包规范CREATE OR REPLACE PACKAGE emp_action_pkg IS v_deptno NUMBER(3):=20; --包公开的变量 --定义一个增加新员工的过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ); --定义一个获取员工加薪数量的函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER; END emp_action_pkg;--定义包体CREATE OR REPLACE PACKAGE BODY emp_action_pkg IS --公开,实现包规范中定义的newdept过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ) AS v_deptcount NUMBER; --保存是否存在员工编号 BEGIN SELECT COUNT (*) INTO v_deptcount FROM dept WHERE deptno = p_deptno; --查询在dept表中是否存在部门编号 IF v_deptcount > 0 --如果存在相同的员工记录 THEN --抛出异常 raise_application_error (-20002, '出现了相同的部门记录'); END IF; INSERT INTO dept(deptno, dname, loc) VALUES (p_deptno, p_dname, p_loc);--插入记录 END newdept; --公开,实现包规范中定义的getraisedsalary函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER IS v_job emp.job%TYPE; --职位变量 v_sal emp.sal%TYPE; --薪资变量 v_salaryratio NUMBER (10, 2); --调薪比率 BEGIN --获取员工表中的薪资信息 SELECT job, sal INTO v_job, v_sal FROM emp WHERE empno = p_empno; CASE v_job --根据不同的职位获取调薪比率 WHEN '职员' THEN v_salaryratio := 1.09; WHEN '销售人员' THEN v_salaryratio := 1.11; WHEN '经理' THEN v_salaryratio := 1.18; ELSE v_salaryratio := 1.1; END CASE; IF v_salaryratio <> 1 --如果有调薪的可能 THEN RETURN ROUND(v_sal * v_salaryratio,2); --返回调薪后的薪资 ELSE RETURN v_sal; --否则不返回薪资 END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 0; --如果没找到原工记录,返回0 END getraisedsalary; --私有,该函数在包规范中并不存在,只能在包体内被引用 FUNCTION checkdeptno(p_deptno dept.deptno%TYPE) RETURN NUMBER AS v_counter NUMBER(2); BEGIN SELECT COUNT(*) INTO v_counter FROM dept WHERE deptno=p_deptno; RETURN v_counter; END; END emp_action_pkg; --代码14.6 调用包组件示例--在该块中为v_deptno赋值为30,调用getraisedsalary函数BEGIN emp_action_pkg.v_deptno:=30; --为包规范变量赋值 DBMS_OUTPUT.put_line(emp_action_pkg.getraisedsalary(7369));--调用包中的函数END;select * from dept;--在该块中为v_deptno赋值为50,并调用newdept过程BEGIN emp_action_pkg.v_deptno:=50; emp_action_pkg.newdept(45,'采纳部','佛山');END;--在该块中输出v_deptno的值BEGIN DBMS_OUTPUT.put_line(emp_action_pkg.v_deptno);END;DELETE FROM dept WHERE deptno=45;--代码14.7 使用SERIALLY_RESUABLE编译提示--定义包规范CREATE OR REPLACE PACKAGE emp_action_pkg IS PRAGMA SERIALLY_REUSABLE; --指定编译提示 v_deptno NUMBER(3):=20; --包公开的变量 --定义一个增加新员工的过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ); --定义一个获取员工加薪数量的函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER; END emp_action_pkg;--定义包体CREATE OR REPLACE PACKAGE BODY emp_action_pkg IS PRAGMA SERIALLY_REUSABLE; --指定编译提示 --公开,实现包规范中定义的newdept过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ) AS v_deptcount NUMBER; --保存是否存在员工编号 BEGIN SELECT COUNT (*) INTO v_deptcount FROM dept WHERE deptno = p_deptno; --查询在dept表中是否存在部门编号 IF v_deptcount > 0 --如果存在相同的员工记录 THEN --抛出异常 raise_application_error (-20002, '出现了相同的员工记录'); END IF; INSERT INTO dept(deptno, dname, loc) VALUES (p_deptno, p_dname, p_loc);--插入记录 END newdept; --公开,实现包规范中定义的getraisedsalary函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER IS v_job emp.job%TYPE; --职位变量 v_sal emp.sal%TYPE; --薪资变量 v_salaryratio NUMBER (10, 2); --调薪比率 BEGIN --获取员工表中的薪资信息 SELECT job, sal INTO v_job, v_sal FROM emp WHERE empno = p_empno; CASE v_job --根据不同的职位获取调薪比率 WHEN '职员' THEN v_salaryratio := 1.09; WHEN '销售人员' THEN v_salaryratio := 1.11; WHEN '经理' THEN v_salaryratio := 1.18; ELSE v_salaryratio := 1; END CASE; IF v_salaryratio <> 1 --如果有调薪的可能 THEN RETURN ROUND(v_sal * v_salaryratio,2); --返回调薪后的薪资 ELSE RETURN v_sal; --否则不返回薪资 END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 0; --如果没找到原工记录,返回0 END getraisedsalary; --私有,该函数在包规范中并不存在,只能在包体内被引用 FUNCTION checkdeptno(p_deptno dept.deptno%TYPE) RETURN NUMBER AS v_counter NUMBER(2); BEGIN SELECT COUNT(*) INTO v_counter FROM dept WHERE deptno=p_deptno; RETURN v_counter; END; END emp_action_pkg; --包的重新编译ALTER PACKAGE emp_action_pkg COMPILE BODY; --编译包体ALTER PACKAGE emp_action_pkg COMPILE PACKAGE; --编译包规范和包体ALTER PACKAGE emp_action_pkg COMPILE SPECIFICATION; --编译包规范--查看包对象和包体对象 SELECT object_type 对象类型, object_name 对象名称, status 状态 FROM user_objects WHERE object_type IN ('PACKAGE', 'PACKAGE BODY') ORDER BY object_type, status, object_name; --查看包规范的源代码 SELECT line, text FROM user_source WHERE NAME = 'EMP_ACTION_PKG' AND TYPE = 'PACKAGE'ORDER BY line;--查看包体的源代码 SELECT line, text FROM user_source WHERE NAME = 'EMP_ACTION_PKG' AND TYPE = 'PACKAGE BODY'ORDER BY line;--代码14.8 在包中重载子程序--定义包规范CREATE OR REPLACE PACKAGE emp_action_pkg_overload IS --定义一个增加新员工的过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ); --定义一个增加新员工的过程,重载过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE --部门名称 ); --定义一个获取员工加薪数量的函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER; --定义一个获取员工加薪数量的函数,重载函数 FUNCTION getraisedsalary (p_ename emp.ename%TYPE) RETURN NUMBER; END emp_action_pkg_overload;--代码14.9 包含重载子程序的包体实现--定义包体CREATE OR REPLACE PACKAGE BODY emp_action_pkg_overload IS --公开,实现包规范中定义的newdept过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ) AS v_deptcount NUMBER; --保存是否存在员工编号 BEGIN SELECT COUNT (*) INTO v_deptcount FROM dept WHERE deptno = p_deptno; --查询在dept表中是否存在部门编号 IF v_deptcount > 0 --如果存在相同的员工记录 THEN --抛出异常 raise_application_error (-20002, '出现了相同的员工记录'); END IF; INSERT INTO dept(deptno, dname, loc) VALUES (p_deptno, p_dname, p_loc);--插入记录 END newdept; PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE --部门名称 ) AS v_deptcount NUMBER; --保存是否存在员工编号 BEGIN SELECT COUNT (*) INTO v_deptcount FROM dept WHERE deptno = p_deptno; --查询在dept表中是否存在部门编号 IF v_deptcount > 0 --如果存在相同的员工记录 THEN --抛出异常 raise_application_error (-20002, '出现了相同的员工记录'); END IF; INSERT INTO dept(deptno, dname, loc) VALUES (p_deptno, p_dname, '中国');--插入记录 END newdept; --公开,实现包规范中定义的getraisedsalary函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER IS v_job emp.job%TYPE; --职位变量 v_sal emp.sal%TYPE; --薪资变量 v_salaryratio NUMBER (10, 2); --调薪比率 BEGIN --获取员工表中的薪资信息 SELECT job, sal INTO v_job, v_sal FROM emp WHERE empno = p_empno; CASE v_job --根据不同的职位获取调薪比率 WHEN '职员' THEN v_salaryratio := 1.09; WHEN '销售人员' THEN v_salaryratio := 1.11; WHEN '经理' THEN v_salaryratio := 1.18; ELSE v_salaryratio := 1; END CASE; IF v_salaryratio <> 1 --如果有调薪的可能 THEN RETURN ROUND(v_sal * v_salaryratio,2); --返回调薪后的薪资 ELSE RETURN v_sal; --否则不返回薪资 END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 0; --如果没找到原工记录,返回0 END getraisedsalary; --重载函数的实现 FUNCTION getraisedsalary (p_ename emp.ename%TYPE) RETURN NUMBER IS v_job emp.job%TYPE; --职位变量 v_sal emp.sal%TYPE; --薪资变量 v_salaryratio NUMBER (10, 2); --调薪比率 BEGIN --获取员工表中的薪资信息 SELECT job, sal INTO v_job, v_sal FROM emp WHERE ename = p_ename; CASE v_job --根据不同的职位获取调薪比率 WHEN '职员' THEN v_salaryratio := 1.09; WHEN '销售人员' THEN v_salaryratio := 1.11; WHEN '经理' THEN v_salaryratio := 1.18; ELSE v_salaryratio := 1; END CASE; IF v_salaryratio <> 1 --如果有调薪的可能 THEN RETURN ROUND(v_sal * v_salaryratio,2); --返回调薪后的薪资 ELSE RETURN v_sal; --否则不返回薪资 END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 0; --如果没找到原工记录,返回0 END getraisedsalary; --私有,该函数在包规范中并不存在,只能在包体内被引用 FUNCTION checkdeptno(p_deptno dept.deptno%TYPE) RETURN NUMBER AS v_counter NUMBER(2); BEGIN SELECT COUNT(*) INTO v_counter FROM dept WHERE deptno=p_deptno; RETURN v_counter; END; END emp_action_pkg_overload; --重载过程调用示例DECLARE v_sal NUMBER(10,2);BEGIN emp_action_pkg_overload.newdept(43,'样品部','东京'); --重载过程使用示例 emp_action_pkg_overload.newdept(44,'纸品部'); v_sal:=emp_action_pkg_overload.getraisedsalary(7369); --重载函数使用示例 v_sal:=emp_action_pkg_overload.getraisedsalary('史密斯');END;--代码14.10 包体初始化单元示例--定义包头,在包头中定义要公开的成员CREATE OR REPLACE PACKAGE InitTest IS TYPE emp_typ IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER; CURSOR emp_cur RETURN emp%ROWTYPE; --定义游标 curr_time NUMBER; --当前秒数 emp_tab emp_typ; --定义集合类型的变量 --定义一个增加新员工的过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ); --定义一个获取员工加薪数量的函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER; END InitTest;--定义包体,在包体的初始化区域对包进行初始化CREATE OR REPLACE PACKAGE BODY InitTest IS row_counter NUMBER:=1; CURSOR emp_cur RETURN emp%ROWTYPE IS SELECT * FROM emp ORDER BY sal DESC; --定义游标体 --定义一个增加新员工的过程 PROCEDURE newdept ( p_deptno dept.deptno%TYPE, --部门编号 p_dname dept.dname%TYPE, --部门名称 p_loc dept.loc%TYPE --位置 ) AS BEGIN NULL; END newdept; --定义一个获取员工加薪数量的函数 FUNCTION getraisedsalary (p_empno emp.empno%TYPE) RETURN NUMBER IS BEGIN NULL; END getraisedsalary;BEGIN --包初始化部分,定义包的代码 SELECT TO_NUMBER(TO_CHAR(SYSDATE,'SSSSS')) INTO curr_time FROM dual; FOR emp_row IN emp_cur LOOP emp_tab(row_counter):=emp_row; --为集合赋值 row_counter:=row_counter+1; END LOOP; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.put_line('出现了异常'); END InitTest;SELECT name,line, POSITION, text FROM user_errors WHERE NAME = 'INITTEST'ORDER BY SEQUENCE;DECLARE v_time NUMBER;BEGIN v_time:=InitTest.curr_time; --获取当前的时间秒数 --输出索引表中的员工名称,以及当前的秒数(应该是初始化时的秒数)。 DBMS_OUTPUT.put_line(InitTest.emp_tab(1).ename||' '||v_time);END;
0 0
- 源码-PL/SQL从入门到精通-第十四章-包-Part 1
- 源码-PL/SQL从入门到精通-第十四章-包-Part 2
- 源码-PL/SQL从入门到精通-第二章-PL/SQL基本概念-Part 1
- 源码-PL/SQL从入门到精通-第十八章-PL/SQL性能优化建议-Part 1
- 源码-PL/SQL从入门到精通-第九章-SQL内置函数-Part 1
- 源码-PL/SQL从入门到精通-第十六章-动态SQL语句-Part 1
- 源码-PL/SQL从入门到精通-第三章-变量和类型-Part 1
- 源码-PL/SQL从入门到精通-第六章-查询数据表-Part 1
- 源码-PL/SQL从入门到精通-第八章-记录与集合-Part 1
- 源码-PL/SQL从入门到精通-第十章-使用游标-Part 1
- 源码-PL/SQL从入门到精通-第十二章-异常处理机制-Part 1
- 源码-PL/SQL从入门到精通-第十三章-子程序-Part 1
- 源码-PL/SQL从入门到精通-第十五章-触发器-Part 1
- 源码-PL/SQL从入门到精通-第十七章-面向对象编程-Part 1
- 源码-PL/SQL从入门到精通-第二章-PL/SQL基本概念-Part 2
- 源码-PL/SQL从入门到精通-第二章-PL/SQL基本概念-Part 3
- 源码-PL/SQL从入门到精通-第十八章-PL/SQL性能优化建议-Part 2
- 源码-PL/SQL从入门到精通-第九章-SQL内置函数-Part 2
- 解决一切的KLTabBarViewController
- BroadleafCommerce数据模型
- Java集合的小抄 Java初学者必备
- maven POM.xml 标签详解
- linux的函数库管理
- 源码-PL/SQL从入门到精通-第十四章-包-Part 1
- jsp设置网页根目录
- Redis 复制原理及分析
- Android View,SurfaceView,GLSurfaceView的关系和区别
- 电子设计竞赛样片申请
- iptables常用命令及应用
- 决策树(六)--随机森林
- Windows下apache虚拟目录
- 前端学习资源