目录
一、概述
什么是包?
包是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合。类似于Java里面的类(class)。包中的程序元素分为两种:公用元素(公用组件)和私用元素(私用组件)。
特点:
- 具有面向对象程序设计语言的特点,是对PL/SQL程序设计元素(过程、函数、变量)的封装。
- 使程序设计模块化
包的组成:一个包由两个公开的部分组成
- 包规范(包定义):用于定义包的公共组件,包括常量、变量、游标、过程和函数等。
- 包体(包主体):用于实现包规范所定义的公用过程和函数。包体不仅可用于实现公用过程和函数,而且还可定义包的私有组件(变量、游标、过程、函数等)。
--创建包规范
CREATE OR REPLACE PACKAGE first_package
IS
v_no emp.deptno%TYPE:=10;
--过程
PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no,v_avgsal OUT NUMBER, v_cnt OUT NUMBER);
END first_package;
--创建包体
CREATE OR REPLACE PACKAGE BODY first_package
IS
PROCEDURE query_emp(v_deptno IN NUMBER DEFAULT v_no,v_avgsal OUT NUMBER, v_cnt OUT NUMBER)
IS
BEGIN
SELECT avg(sal), count(*)
INTO v_avgsal, v_cnt
FROM emp
WHERE deptno = v_deptno;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('没有此部门!');
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
END first_package;
--调用
DECLARE
v_avgsal NUMBER;
v_cnt NUMBER;
BEGIN
first_package.query_emp(20,v_avgsal,v_cnt);
--v_deptno采用默认值时,需要使用名称传递这种传值方式
--first_package.query_emp(v_avgsal => v_avgsal,v_cnt => v_cnt);
DBMS_OUTPUT.put_line('平均工资:'||v_avgsal);
DBMS_OUTPUT.put_line('总人数:'||v_cnt);
END;
二、包的创建
--创建包规范
CREATE OR REPLACE PACKAGE emp_package
IS
--添加员工信息的存储过程
PROCEDURE add_emp_proc
(v_empno IN emp.empno%TYPE,
v_ename IN emp.ename%type,
v_sal IN emp.sal%type,
v_deptno IN emp.deptno%type);
--删除员工信息的存储过程
PROCEDURE del_emp_proc
(v_empno IN emp.empno%type);
END emp_package;
--创建包体
CREATE OR REPLACE PACKAGE BODY emp_package
IS
--添加员工信息的存储过程
PROCEDURE add_emp_proc
(v_empno IN emp.empno%TYPE,
v_ename IN emp.ename%type,
v_sal IN emp.sal%type,
v_deptno IN emp.deptno%type)
IS
e_2291 EXCEPTION;
PRAGMA EXCEPTION_INIT(e_2291,-2291);
BEGIN
INSERT INTO emp(empno, ename, sal, deptno) VALUES(v_empno,v_ename,v_sal,v_deptno);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
RAISE_APPLICATION_ERROR(-20001,'员工号不能重复');
WHEN e_2291 THEN
RAISE_APPLICATION_ERROR(-20008,'部门号不存在');
END;
--删除员工信息的存储过程
PROCEDURE del_emp_proc
(v_empno IN emp.empno%type)
IS
BEGIN
--根据员工号删除指定的员工信息
DELETE FROM emp WHERE empno = v_empno;
--判断是否删除成功
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20009,'指定删除的员工不存在');
ELSE
DBMS_OUTPUT.put_line('删除成功');
END IF;
END;
END emp_package;
--根据员工号查询工资,如果工资小于等于3000,工资涨500.
--创建包规范
CREATE OR REPLACE PACKAGE emp_sal_pkg
IS
FUNCTION get_sal(eno NUMBER)RETURN NUMBER;
PROCEDURE upd_sal(eno NUMBER, salary NUMBER);
END emp_sal_pkg;
--包体
CREATE OR REPLACE PACKAGE BODY emp_sal_pkg
IS
--根据员工号查询员工的工资
FUNCTION get_sal(eno NUMBER)RETURN NUMBER
IS
v_sal emp.sal%TYPE:= 0;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE empno = eno;
RETURN v_sal;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20008,'此员工号不存在!');
END;
--更新满足条件的员工的工资
PROCEDURE upd_sal(eno NUMBER, salary NUMBER)
IS
BEGIN
IF salary<=3000 THEN
UPDATE emp SET sal = sal + 500 WHERE empno = eno;
END IF;
END;
END emp_sal_pkg;
三、包的调用与删除
--示例一:调用emp_package包下添加员工信息的存储过程
DECLARE
v_empno emp.empno%TYPE:=&empno;
v_ename emp.ename%TYPE:='&name';
v_sal emp.sal%TYPE:=&salary;
v_deptno emp.deptno%TYPE:=&deptno;
e_dup_val EXCEPTION;
e_no_dept EXCEPTION;
PRAGMA EXCEPTION_INIT(e_dup_val,-20001);
PRAGMA EXCEPTION_INIT(e_no_dept,-20008);
BEGIN
emp_package.add_emp_proc(v_empno,v_ename,v_sal,v_deptno);
COMMIT;
EXCEPTION
WHEN e_dup_val THEN
DBMS_OUTPUT.put_line(SQLERRM);
WHEN e_no_dept THEN
DBMS_OUTPUT.put_line(SQLERRM);
ROLLBACK;
END;
SELECT * FROM EMP;
--示例二:调用emp_package包下删除指定员工的存储过程
DECLARE
v_empno emp.empno%TYPE:=&empno;
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp,-20009);
BEGIN
emp_package.del_emp_proc(v_empno);
COMMIT;
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
ROLLBACK;
END;
--示例三:调用emp_sal_pkg包下函数和过程
DECLARE
v_empno emp.empno%TYPE := &empno;
v_salary emp.sal%TYPE;
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp,-20008);
BEGIN
v_salary:= emp_sal_pkg.get_sal(v_empno);
emp_sal_pkg.upd_sal(v_empno,v_salary);
COMMIT;
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
--用SQLPLUS命令调用(下述命令请在command窗口或SQLPLUS窗口执行)
/*
VAR v_empno NUMBER
EXEC :v_empno := &no
VAR v_salary NUMBER
EXEC :v_salary := emp_sal_pkg.get_sal(:v_empno)
EXEC emp_sal_pkg.upd_sal(:v_empno, :v_salary)
*/
--删除包
DROP PACKAGE first_package;
--删除包体
DROP PACKAGE BODY first_package;
四、子程序重载
子程序重载是指两个或多个子程序有相同的名称,但拥有不同的参数变量、参数顺序或参数数据类型。
--根据员工号或员工姓名获取员工的信息
--根据员工号或员工姓名删除员工的信息
--创建包规范
CREATE OR REPLACE PACKAGE overload_pkg
IS
FUNCTION get_info(eno NUMBER) RETURN emp%ROWTYPE;
FUNCTION get_info(name VARCHAR2) RETURN emp%ROWTYPE;
PROCEDURE del_emp(eno NUMBER);
PROCEDURE del_emp(name VARCHAR2);
END;
--创建包体
CREATE OR REPLACE PACKAGE BODY overload_pkg
IS
FUNCTION get_info(eno NUMBER) RETURN emp%ROWTYPE
IS
emp_record emp%ROWTYPE;
BEGIN
SELECT * INTO emp_record FROM emp WHERE empno = eno;
RETURN emp_record;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20020,'不存在此员工!');
END;
FUNCTION get_info(name VARCHAR2) RETURN emp%ROWTYPE
IS
emp_record emp%ROWTYPE;
BEGIN
SELECT * INTO emp_record FROM emp WHERE ename = name;
RETURN emp_record;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20020,'不存在此员工!');
END;
PROCEDURE del_emp(eno NUMBER)
IS
BEGIN
DELETE FROM emp WHERE empno = eno;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20020,'不存在此员工');
END IF;
END;
PROCEDURE del_emp(name VARCHAR2)
IS
BEGIN
DELETE FROM emp WHERE ename = name;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20020,'不存在此员工');
END IF;
END;
END;
--调用
--根据员工号查询员工信息
DECLARE
emp_record emp%rowtype;
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp,-20020);
BEGIN
emp_record:= overload_pkg.get_info(&no);
DBMS_OUTPUT.PUT_LINE('员工号:'||emp_record.empno||'姓名:'||emp_record.ename||'工资:'||emp_record.sal);
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
--根据员工姓名查询员工信息
DECLARE
emp_record emp%rowtype;
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp,-20020);
BEGIN
emp_record:= overload_pkg.get_info('&name');
DBMS_OUTPUT.PUT_LINE('员工号:'||emp_record.empno||'姓名:'||emp_record.ename||'工资:'||emp_record.sal);
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
--根据员工号删除员工信息
DECLARE
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp, -20020);
BEGIN
overload_pkg.del_emp(&no);
COMMIT;
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
ROLLBACK;
END;
SELECT * FROM EMP;
--根据员工的姓名删除员工的信息
DECLARE
e_no_emp EXCEPTION;
PRAGMA EXCEPTION_INIT(e_no_emp, -20020);
BEGIN
overload_pkg.del_emp('&name');
COMMIT;
EXCEPTION
WHEN e_no_emp THEN
DBMS_OUTPUT.put_line(SQLERRM);
ROLLBACK;
END;