游标(CURSOR) 用户定义的数据操作缓存区,在可执行部分使用 类型(TYPE) 用户定义的新的结构类型
异常(EXCEPTION) 在标准包中定义或由用户自定义,用于处理程序错误 过程(PROCUDURE) 带参数的命名的程序模块
函数(FUNCTION) 带参数、具有返回值的命名的程序模块 变量(VARIABLE) 存储变化的量的存储单元 常量(CONSTANT) 存储不变的量的存储单元
游标(CURSOR) 用户定义的数据操作缓存区,在可执行部分使用 类型(TYPE) 用户定义的新的结构类型
异常(EXCEPTION) 在标准包中定义或由用户自定义,用于处理程序错误
说明部分可以出现在包的三个不同的部分:出现在包头中的称为公有元素,出现在包体中的称为私有元素,出现在包体的过程(或函数)中的称为局部变量。它们的性质有所不同,如下所示。 Sql代码
公有元素(PUBLIC) 在包头中说明,在包体中具体定义 在包外可见并可以访问,对整个应用的全过程有效
私有元素(PRIVATE) 在包体的说明部分说明 只能被包内部的其他部分访问
局部变量(LOCAL) 在过程或函数的说明部分说明 只能在定义变量的过程或函数中使用 公有元素(PUBLIC) 在包头中说明,在包体中具体定义 在包外可见并可以访问,对整个应用的全过程有效
私有元素(PRIVATE) 在包体的说明部分说明 只能被包内部的其他部分访问
局部变量(LOCAL) 在过程或函数的说明部分说明 只能在定义变量的过程或函数中使用 在包体中出现的过程或函数,如果需要对外公用,就必须在包头中说明,包头中的说明应该和包体中的说明一致。 包有以下优点:
* 包可以方便地将存储过程和函数组织到一起,每个包又是相互独立的。在不同的包中,过程、函数都可以重名,这解决了在同一个用户环境中命名的冲突问题。 * 包增强了对存储过程和函数的安全管理,对整个包的访问权只需一次授予。 * 在同一个会话中,公用变量的值将被保留,直到会话结束。
* 区分了公有过程和私有过程,包体的私有过程增加了过程和函数的保密性。
* 包在被首次调用时,就作为一个整体被全部调入内存,减少了多次访问过程或函数的I/O次数。 创建包和包体
包由包头和包体两部分组成,包的创建应该先创建包头部分,然后创建包体部分。创建、删除和编译包的权限同创建、删除和编译存储过程的权限相同。 创建包头的简要语句如下:
CREATE [OR REPLACE] PACKAGE 包名 {IS|AS} 公有变量定义 公有类型定义 公有游标定义 公有异常定义 函数说明 过程说明 END;
创建包体的简要语法如下:
CREATE [OR REPLACE] PACKAGE BODY 包名 {IS|AS} 私有变量定义 私有类型定义 私有游标定义 私有异常定义 函数定义 过程定义 END;
包的其他操作命令包括: 删除包头:
DROP PACKAGE 包头名 删除包体:
DROP PACKAGE BODY 包体名 重新编译包头:
ALTER PACKAGE 包名 COMPILE PACKAGE 重新编译包体:
ALTER PACKAGE 包名 COMPILE PACKAGE BODY
在包头中说明的对象可以在包外调用,调用的方法和调用单独的过程或函数的方法基本相同,惟一的区别就是要在调用的过程或函数名前加上包的名字(中间用“.”分隔)。但要注意,不同的会话将单独对包的公用变量进行初始化,所以不同的会话对包的调用属于不同的应用。 系统包
Oracle预定义了很多标准的系统包,这些包可以在应用中直接使用,比如在训练中我们使用的DBMS_OUTPUT包,就是系统包。PUT_LINE是该包的一个函数。常用系统包下所示。 Sql代码
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语句
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语句 包的应用
在SQL*Plus环境下,包和包体可以分别编译,也可以一起编译。如果分别编译,则要先编译包头,后编译包体。如果在一起编译,则包头写在前,包体在后,中间用“/”分隔。 可以将已经存在的存储过程或函数添加到包中,方法是去掉过程或函数创建语句的CREATE OR REPLACE部分,将存储过程或函数复制到包体中 ,然后重新编译即可。
如果需要将私有过程或函数变成共有过程或函数的话,将过程或函数说明部分复制到包头说明部分,然后重新编译就可以了。
【训练1】 创建管理雇员信息的包EMPLOYE,它具有从EMP表获得雇员信息,修改雇员名称,修改雇员工资和写回EMP表的功能。 步骤1:登录SCOTT账户,输入以下代码并编译: Sql代码
CREATE OR REPLACE PACKAGE EMPLOYE --包头部分 IS
PROCEDURE SHOW_DETAIL;
PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER);
PROCEDURE SAVE_EMPLOYE;
PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2); PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER); END EMPLOYE; /
CREATE OR REPLACE PACKAGE BODY EMPLOYE --包体部分 IS
EMPLOYE EMP%ROWTYPE;
-------------- 显示雇员信息 --------------- PROCEDURE SHOW_DETAIL AS BEGIN
DBMS_OUTPUT.PUT_LINE(?----- 雇员信息 -----?);
DBMS_OUTPUT.PUT_LINE('雇员编号:'||EMPLOYE.EMPNO); DBMS_OUTPUT.PUT_LINE('雇员名称:'||EMPLOYE.ENAME); DBMS_OUTPUT.PUT_LINE('雇员职务:'||EMPLOYE.JOB); DBMS_OUTPUT.PUT_LINE('雇员工资:'||EMPLOYE.SAL); DBMS_OUTPUT.PUT_LINE('部门编号:'||EMPLOYE.DEPTNO); END SHOW_DETAIL;
----------------- 从EMP表取得一个雇员 --------------------
PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER) AS BEGIN
SELECT * INTO EMPLOYE from EMP WHERE EMPNO=P_EMPNO; DBMS_OUTPUT.PUT_LINE('获取雇员'||EMPLOYE.ENAME||'信息成功'); EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('获取雇员信息发生错误!'); END GET_EMPLOYE;
---------------------- 保存雇员到EMP表 -------------------------- PROCEDURE SAVE_EMPLOYE AS BEGIN
UPDATE EMP SET ENAME=EMPLOYE.ENAME, SAL=EMPLOYE.SAL WHERE EMPNO=
EMPLOYE.EMPNO;
DBMS_OUTPUT.PUT_LINE('雇员信息保存完成!'); END SAVE_EMPLOYE;
---------------------------- 修改雇员名称 ------------------------------
PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2) AS BEGIN
EMPLOYE.ENAME:=P_NEWNAME;
DBMS_OUTPUT.PUT_LINE('修改名称完成!'); END CHANGE_NAME;
---------------------------- 修改雇员工资 -------------------------- PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER) AS BEGIN
EMPLOYE.SAL:=P_NEWSAL;
DBMS_OUTPUT.PUT_LINE('修改工资完成!'); END CHANGE_SAL; END EMPLOYE;
CREATE OR REPLACE PACKAGE EMPLOYE --包头部分 IS
PROCEDURE SHOW_DETAIL;
PROCEDURE GET_EMPLOYE(P_EMPNO NUMBER); PROCEDURE SAVE_EMPLOYE;
PROCEDURE CHANGE_NAME(P_NEWNAME VARCHAR2); PROCEDURE CHANGE_SAL(P_NEWSAL NUMBER); END EMPLOYE; /
CREATE OR REPLACE PACKAGE BODY EMPLOYE --包体部分 IS
EMPLOYE EMP%ROWTYPE; -------------- 显示雇员信息 --------------- PROCEDURE SHOW_DETAIL AS BEGIN
DBMS_OUTPUT.PUT_LINE(?----- 雇员信息 -----?);
DBMS_OUTPUT.PUT_LINE('雇员编号:'||EMPLOYE.EMPNO); DBMS_OUTPUT.PUT_LINE('雇员名称:'||EMPLOYE.ENAME);