博客
关于我
Oracle进阶(六)包(Package)和包体
阅读量:332 次
发布时间:2019-03-04

本文共 8962 字,大约阅读时间需要 29 分钟。

1、包(Package)概述

包(Package)是用来存储相关程序结构的对象,它存储于数据字典中。包由两部分组成:包规范(PACKAGE)和包体(PACKAGE BODY)。

包规范是包的说明部分,是对外的操作接口(类似java接口),对应用是可见的。

包体是包的代码和实现部分(类似java实现类),对应用来说是不可见的。

1.1 包说明

公有元素(PUBLIC)    在包头中说明,在包体中具体定义。在包外可见并可以访问,对整个应用的全过程有效。

私有元素(PRIVATE)  在包体的说明部分说明。只能被包内部的其他部分访问。
局部变量(LOCAL)     在过程或函数的说明部分说明。只能在定义变量的过程或函数中使用。

1.2 系统包

包名称 描述
DBMS_OUTPUT 在SQL*Plus环境下输出信息
DBMS_DDL 编译过程函数和包
DBMS_SESSION 改变用户的会话,初始化包等
DBMS_TRANSACTION 控制数据库事务
DBMS_MAIL 连接Oracle*Mail
DBMS_LOCK 进行复杂的锁机制管理
DBMS_ALERT 识别数据库事件告警
DBMS_PIPE 通过管道在会话间传递信息
DBMS_JOB 管理Oracle的作业
DBMS_LOB 操纵大对象
DBMS_SQL 执行动态SQL语句

2、基本语法

2.1 创建包和包体

1.创建包规范语法:        CREATE [OR REPLACE] PACKAGE 包名 IS|AS           --变量(VARIABLE)定义           --常量(CONSTANT)定义           --游标(CURSOR)定义           --类型(TYPE)定义           --函数定义           FUNCTION 函数名 [(参数列表)] RETURN 返回类型;           --存储过程定义           PROCEDURE 存储过程名 [(参数列表)];           异常(EXCEPTION)        END [包名]; 2.创建包体语法:        CREATE [OR REPLACE] PACKAGE BODY 包名 IS|AS           --...           --函数实现           FUNCTION 函数名 [(参数列表)] RETURN 返回类型 IS|AS           --函数实现内容           --存储过程实现           PROCEDURE 存储过程名 [(参数列表)] IS|AS           --存储过程实现内容       END [包名];

2.2 其它语法

--1 删除包规范DROP PACKAGE 包规范名--2 删除包体DROP PACKAGE BODY 包体名--3 重新编译包头ALTER PACKAGE 包名 COMPILE PACKAGE--4 重新编译包体ALTER PACKAGE 包名 COMPILE PACKAGE BODY

2.3 注意要点

1 包说明和包体必须有相同的名字

2 包的开始没有BEGIN语句,与存储过程和函数不同。
3 在包的说明部分定义函数和过程的名称和参数,具体实现在包体中定义。
4 在包内声明常量、变量、类型定义、异常、及游标时不使用DECLARE。
5 包内的过程和函数的定义不要CREATE OR REPLACE语句。
6 包定义和包体两者分离。
7 只有当包头编辑成功后才能编辑包体。
8 函数名与过程名须和包头中的函数过程一样。

3、包的应用

以下所涉及的表,请查看的附表。

3.1 包创建

CREATE OR REPLACE PACKAGE EMP_PK           --包定义部分             IS  				--公有变量:员工人数         V_EMP_COUNT NUMBER(5);				--公有过程:初始化数据         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER);				--公有过程:显示员工列表          PROCEDURE LIST_EMP;				 --公有过程:新增员工         PROCEDURE INSERT_EMP(P_EMPNO NUMBER,P_ENAME VARCHAR2,P_JOB VARCHAR2,P_SAL NUMBER);				 --公有过程:删除员工         PROCEDURE DELETE_EMP(P_EMPNO NUMBER);				 --公有过程:修改员工工资         PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER);        END EMP_PK;                    /           CREATE OR REPLACE PACKAGE BODY EMP_PK        --包体部分             IS           --私有变量:输出信息         V_MESSAGE VARCHAR2(50);         --私有变量:可修改工资上限          V_MAX_SAL NUMBER(7);         --私有变量:可修改工资下限           V_MIN_SAL NUMBER(7);         --私有函数:判断员工是否存在         FUNCTION EXIST_EMP(P_EMPNO NUMBER)  RETURN  BOOLEAN;         --私有过程:显示信息         PROCEDURE SHOW_MESSAGE;         --INIT         PROCEDURE INIT(P_MAX NUMBER,P_MIN NUMBER)             IS            BEGIN            SELECT COUNT(*) INTO V_EMP_COUNT FROM EMP;            V_MAX_SAL:=P_MAX;            V_MIN_SAL:=P_MIN;            V_MESSAGE:='初始化数据已完成!';            SHOW_MESSAGE;            END INIT;           --LIST_EMP         PROCEDURE LIST_EMP             IS            BEGIN            DBMS_OUTPUT.PUT_LINE('姓名       职务      工资');            FOR EMP_REC IN (SELECT ENAME,JOB,SAL FROM EMP)            LOOP             DBMS_OUTPUT.PUT_LINE(RPAD(EMP_REC.ENAME,10,' ')||RPAD(EMP_REC.JOB,10,' ')||TO_CHAR(EMP_REC.SAL));            END LOOP;            DBMS_OUTPUT.PUT_LINE('员工总人数'|| V_EMP_COUNT);           END LIST_EMP;          --INSERT_EMP          PROCEDURE INSERT_EMP(P_EMPNO NUMBER,P_ENAME VARCHAR2,P_JOB VARCHAR2,P_SAL NUMBER)            IS            BEGIN            IF NOT EXIST_EMP(P_EMPNO) THEN             INSERT INTO EMP(EMPNO,ENAME,JOB,SAL)VALUES(P_EMPNO,P_ENAME,P_JOB,P_SAL);             COMMIT;              V_EMP_COUNT:=V_EMP_COUNT+1;             V_MESSAGE:='员工'||P_EMPNO||'已新增!';            ELSE             V_MESSAGE:='员工'||P_EMPNO||'已存在,不能新增!';            END IF;             SHOW_MESSAGE;            EXCEPTION            WHEN OTHERS THEN            V_MESSAGE:='员工'||P_EMPNO||'新增失败!';            SHOW_MESSAGE;           END INSERT_EMP;          --DELETE_EMP         PROCEDURE DELETE_EMP(P_EMPNO NUMBER)             IS            BEGIN             IF EXIST_EMP(P_EMPNO) THEN             DELETE FROM EMP WHERE EMPNO=P_EMPNO;             COMMIT;             V_EMP_COUNT:=V_EMP_COUNT-1;             V_MESSAGE:='员工'||P_EMPNO||'已删除!';            ELSE             V_MESSAGE:='员工'||P_EMPNO||'不存在,不能删除!';            END IF;            SHOW_MESSAGE;           EXCEPTION            WHEN OTHERS THEN            V_MESSAGE:='员工'||P_EMPNO||'删除失败!';            SHOW_MESSAGE;           END DELETE_EMP;           --CHANGE_EMP_SAL           PROCEDURE CHANGE_EMP_SAL(P_EMPNO NUMBER,P_SAL NUMBER)             IS            BEGIN             IF (P_SAL>V_MAX_SAL OR P_SAL

3.2 包调用

--调用包--1 初始化BEGIN  EMP_PK.INIT(P_MAX => 200,              P_MIN => 100);END;--2 员工列表CALL EMP_PK.LIST_EMP();--3 新增员工CALL EMP_PK.INSERT_EMP(2021,'一二山人','YESR',10000);  --4 查看员工人数BEGIN      DBMS_OUTPUT.PUT_LINE(EMP_PK.V_EMP_COUNT);  END;--5 删除员工CALL EMP_PK.DELETE_EMP(2021); --6 修改工资CALL EMP_PK.CHANGE_EMP_SAL(7900,150); --7 授权其他用户调用包GRANT EXECUTE ON EMP_PK TO SYS;  --8 其它用户SYS调用包CALL SCOTT.EMP_PK.INIT(400,300);

4、包的进阶

4.1 包重载创建

CREATE OR REPLACE PACKAGE EMP_OVERLOAD_PK IS   --过程:新增部门   PROCEDURE INSERT_DEPT (       P_DEPTNO   DEPT.DEPTNO%TYPE,    --部门编号       P_DNAME    DEPT.DNAME%TYPE,     --部门名称       P_LOC      DEPT.LOC%TYPE        --位置    );      --过程:新增部门(重载)   PROCEDURE INSERT_DEPT (       P_DEPTNO   DEPT.DEPTNO%TYPE,    --部门编号       P_DNAME    DEPT.DNAME%TYPE     --部门名称    );           --函数:获取员工加薪    FUNCTION GET_ADDSALARY (P_EMPNO EMP.EMPNO%TYPE)       RETURN NUMBER;    --函数:获取员工加薪(重载)    FUNCTION GET_ADDSALARY (P_ENAME EMP.ENAME%TYPE)       RETURN NUMBER;                  END EMP_OVERLOAD_PK;/CREATE OR REPLACE PACKAGE BODY EMP_OVERLOAD_PKIS    FUNCTION EXIST_DEPT(P_DEPTNO DEPT.DEPTNO%TYPE)  RETURN  NUMBER;  --INSERT_DEPT  PROCEDURE INSERT_DEPT (       P_DEPTNO   DEPT.DEPTNO%TYPE,       P_DNAME    DEPT.DNAME%TYPE,       P_LOC      DEPT.LOC%TYPE    )    AS       BEGIN       IF EXIST_DEPT(P_DEPTNO) > 0  --如果部门存在       THEN                            --抛出异常          RAISE_APPLICATION_ERROR (-2021, '出现了相同的员工记录');       END IF;       INSERT INTO DEPT(DEPTNO, DNAME, LOC)            VALUES (P_DEPTNO, P_DNAME, P_LOC);--新增						COMMIT;    END INSERT_DEPT;--INSERT_DEPT(重载)  PROCEDURE INSERT_DEPT (       P_DEPTNO   DEPT.DEPTNO%TYPE,       P_DNAME    DEPT.DNAME%TYPE    )    AS       BEGIN       IF EXIST_DEPT(P_DEPTNO) > 0 --如果部门存在       THEN                            --抛出异常          RAISE_APPLICATION_ERROR (-2022, '出现了相同的员工记录');       END IF;       INSERT INTO DEPT(DEPTNO, DNAME, LOC)            VALUES (P_DEPTNO, P_DNAME, '广州天河区');--新增记录						COMMIT;    END INSERT_DEPT;    --GET_ADDSALARY    FUNCTION GET_ADDSALARY (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 'CLERK' THEN             V_SALARYRATIO := 1.05;          WHEN 'SALESMAN' THEN             V_SALARYRATIO := 1.1;          WHEN 'MANAGER' THEN             V_SALARYRATIO := 1.2;          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;     END GET_ADDSALARY;    --GET_ADDSALARY(重载)    FUNCTION GET_ADDSALARY (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 'CLERK' THEN             V_SALARYRATIO := 1.05;          WHEN 'SALESMAN' THEN             V_SALARYRATIO := 1.1;          WHEN 'MANAGER' THEN             V_SALARYRATIO := 1.2;          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;     END GET_ADDSALARY;    --私有函数:部门是否存在    FUNCTION EXIST_DEPT(P_DEPTNO DEPT.DEPTNO%TYPE) RETURN NUMBER    AS      V_COUNT NUMBER(2);    BEGIN       SELECT COUNT(*) INTO V_COUNT FROM DEPT WHERE DEPTNO=P_DEPTNO;       RETURN V_COUNT;    END;END EMP_OVERLOAD_PK;

4.2 包重载调用

--调用BEGIN	 EMP_OVERLOAD_PK.INSERT_DEPT(50,,);END--重载过程BEGIN  EMP_OVERLOAD_PK.INSERT_DEPT(P_DEPTNO => 50,                              P_DNAME =>'交付二部',                              P_LOC => '海珠区');END;--过程BEGIN  EMP_OVERLOAD_PK.INSERT_DEPT(P_DEPTNO => 60,                              P_DNAME =>'交付一部');END;----重载函数DECLARE   V_SAL NUMBER(10,2);BEGIN   V_SAL:=EMP_OVERLOAD_PK.GET_ADDSALARY(7369);	 DBMS_OUTPUT.PUT_LINE('获取员工加薪'|| V_SAL); END;--函数DECLARE   V_SAL NUMBER(10,2);BEGIN   V_SAL:=EMP_OVERLOAD_PK.GET_ADDSALARY('SMITH');	 DBMS_OUTPUT.PUT_LINE('获取员工加薪'|| V_SAL); END;

 

转载地址:http://xodh.baihongyu.com/

你可能感兴趣的文章
mysql 查询,正数降序排序,负数升序排序
查看>>
MySQL 树形结构 根据指定节点 获取其下属的所有子节点(包含路径上的枝干节点和叶子节点)...
查看>>
mysql 死锁 Deadlock found when trying to get lock; try restarting transaction
查看>>
mysql 死锁(先delete 后insert)日志分析
查看>>
MySQL 死锁了,怎么办?
查看>>
MySQL 深度分页性能急剧下降,该如何优化?
查看>>
MySQL 深度分页性能急剧下降,该如何优化?
查看>>
MySQL 添加列,修改列,删除列
查看>>
mysql 添加索引
查看>>
MySQL 添加索引,删除索引及其用法
查看>>
mysql 状态检查,备份,修复
查看>>
MySQL 用 limit 为什么会影响性能?
查看>>
MySQL 用 limit 为什么会影响性能?有什么优化方案?
查看>>
MySQL 用户权限管理:授权、撤销、密码更新和用户删除(图文解析)
查看>>
mysql 用户管理和权限设置
查看>>
MySQL 的 varchar 水真的太深了!
查看>>
mysql 的GROUP_CONCAT函数的使用(group_by 如何显示分组之前的数据)
查看>>
MySQL 的instr函数
查看>>
MySQL 的mysql_secure_installation安全脚本执行过程介绍
查看>>
MySQL 的Rename Table语句
查看>>