(转自:http://blog.csdn.net/bbliutao/article/details/9016947)

一、概述
包可将一些有联系的对象放在其内部。
任何能在块定义部分出现的对象都可以在包中出现。这些对象包括存储过程、函数、游标、自定义的类型和变量。
我们可以在其它的PLSQL块中引用包中的这些对象,也就是说,包为PLSQL提供了全局变量。
包可以实现信息屏蔽和子程序重载。

二、包的定义
一个包由两个独立部分组成——包头和包体,各部分被单独存放在数据字典中,定义一个包,要分别定义包头和包体。

1、定义包头
(1)、语法:
create or replace package [schema.] package_name {is|as}
pl/sql_package;

其中package_name是包的名称,pl/sql_package可以是存储过程、函数、变量、类型、异常及游标的定义。

存储过程和函数必须在包头中预定义。也就是说,在包头中仅定义存储过程名或函数名以及它们的参数,
存储过程或函数的执行代码将在包体中定义,这不同于无名块中定义存储过程和函数。

例一:
create or replace package aupack as
procedure qusalary(p_code auths.code%type,p_salary out auths.salary%type);
procedure inauthor(p_code auths.code%type,p_salary out auths.salary%type);
end aupack;

2、定义包体
包体是有个数据字典对象。只有在包头成功编译后,包体才能被编译。包体只包含包头中已预定义的子程序代码。
在包头中定义(不是预定义)的对象可以直接在包体中使用,不必再在包体中定义。

(1)、语法:
create or replace package body [schema.] package_name {is/as}
pl/sql_body;

其中package_name为包名,该包名必须与定义包头时的名称一样,pl/sql_body为过程与函数的定义

如果包头不包含存储过程和函数,则不必定义包体。如果包头中有预定义的子程序(存储过程和函数),
则在包体中必须编写其子程序代码,而且包头和包体两部分指定的子程序必须一致。
这包括相同的子程序名、参数名、和参数类型。

例一:
create or replace package body aupack is
procedure qusalary(p_code auths.code%type,p_salary out auths.salary%type) as
begin
...
end aupack;
procedure inauthor(p_code auths.code%type,p_salary out auths.salary%type) as
begin
...
end inauthor;

三、包的初始化

1、概述
包的初始化,也称包的构造过程。类似于C++的构造函数和JAVA的构造方法。
当在会话内第一次被调用时会自动执行,并且在同一会话内只会执行一次。
包的构造过程没有名称,在包体实现了包头定义的子程序后的最后部分被定义,以begin开始、end结束。

2、语法
create or replace package body package_name {is|as}
... --实现包体中过程与函数的定义部分
begin
... --初始化代码
end;

例子
create or replace package apack as
v_sex varchar2(2);
procedure a_sex(p_code auths.code%type,p_sex out varchar2);
end apack;

create or replace body apack as
procedure a_sex(p_code auths.code%type,p_sex out varchar2) as
v_sex number;
begin
select sex into v_sex from auths where code=p_code;
if v_sex=0 then
p_sex:='女';
else
p_sex:='男';
end if;
end apack;
begin
a_sex('A0001',v_sex); --初始化部分
end apack;

四、包中子程序的重载
1、定义
在包的内部,存储过程和函数都可被重载,这意味着有多个存储过程或函数可以使用同一名称,但是参数不能相同。
这样就允许不同的参数调用同一名字的过程或函数。但需要注意同名的函数返回值得数据类型必须完全相同。

例一
create or replace package pac_temp is
procedure ad(p_in number);
procedure ad(p_in varchar2);
end pac_temp;

create or replace package body pac_temp is
procedure ad(p_in number) as
begin
dbms_output.put_line(p_in);
dbms_output.put_line('我是number');
end ad;

procedure ad(p_in varchar2) as
begin
dbms_output.put_line(p_in);
dbms_output.put_line('我是varchar2');
end ad;
end pac_temp;

begin
dbms_output.put_line('a');
pac_temp.ad('5');
pac_temp.ad(5);
end;

2、重载的局限性
(1)、当仅仅参数名不同或者是模式(in,out,in out)不同时,不能重载。
(2)、不能对仅有返回类型不同的函数进行重载。
(3)、重载函数的参数必须是数据类型不同间不可自动转换的。此类错误在编译时不会报错,但调用若自动转换发生错误会报错。

五、包的删除
drop package body pac_name; --只删除包体
drop package pac_name; --删除包

六、包函数的使用纯度级别

1、概述
首先,应该明确这里说的是包里面的函数。要在sql语句中引用包的函数,那么该函数不能含有DML语句,也不能读写远程包的变量。
为了对包的函数加以限制,在定义包头时使用可以使用纯度级别限制函数。

2、语法
pragma restrict_references(function_name,wnds[,wnps,rnds,rnps]); --能在sql语句中调用的函数都有wnds基本约束

四种约束的含义:
WNDS:函数内不能修改数据库数据(即禁止DML操作)。
WNPS:函数内不能修改包变量(即不能给包变量赋值)。
RNDS:函数内不能读取数据数据(即禁止执行select操作)。
RNPS:函数内不能读取包变量(即不能将包变量赋值给其他变量)。

根据对函数的四种基本约束,满足下面约束的函数可以被sql语句调用:
(1)、当函数满足WNDS时,能被SQL语句调用。
(2)、当函数满足RNPS和WNPS约束时,这个函数(通过数据库连接)能被远程或并行调用。
(3)、在select、valules或set子句中调用的函数可以没有wnps约束,但在其它的子句中就必须满足wnps约束。
(4)、一个函数所调用的子程序与该函数的约束级别相同。
(5)、在含有create table或alter table 命令的check子句中,不能调用直接创建的函数,因为这些语句中的定义不能变化。

3、restrict_references编译指令的应用

当将单独存储在数据库中的函数用在sql语句时,plsql引擎自动确定该函数有哪些约束,这些约束能否保证函数在sql语句中的调用。
对于包函数,则先在包内部使用restrict_references编译指令来指定包函数的约束。
在sql语句中调用这个包函数时,plsql根据编译指令指定的约束来来判断包函数能否在sql语句中调用。

例一:
create or replace package authorpack as
function fun(p_authorcode auths.author_code%type) return varchar2;
pragma restrict_references(fun,WNDS,WNPS,RNPS); --指定3种约束
function authorcount return number;
pragma restrict_references(authorcount,WNDS,WNPS,RNPS)
end authorpack;

create or replace body authorpack as
v_num number; --包变量
function fun(p_authorcode auths.author_code%type) return varchar2 as
v_return varchar2(16);
begin
select author||name into v_return from auths where author_code=p_authorcode;
return v_return;
end fun;

function authorcount return number as
v_return number;
begin
if v_num is null then --包变量被读,不满足RNPS
select count(*) into v_return from auths where author_code like 'A%';
v_num:=v_return; --包变量被修改,不满足WNPS
else
v_return:=v_num;
end if;
return v_return;
end authorcount;
end authorpack;

例二
create or replace package purity is
minsal number(6,2);
maxsal number(6,2);
function max_sal return number;
function min_sal return number;
pragma restrict_references(max_sal,WNPS);
pragma restrict_references(min_sal,WNPS);
end;

create or replace package body purity is
function max_sal return number is
begin
select max(sql) into maxsal from emp; --违反WNPS
return maxsal;
end;
function min_sal return number is
begin
select max(sql) into maxsal from emp; --违反WNPS
return maxsal;
end;
end;

在包头的fun函数中使用了restrict_references编译指令指定约束,包体中的fun函数代码显然符合编译指令指定的约束——没有修改数据库表、没有读包中变量、没有修改包中变量。
在包头的authorcount函数中使用了restrict_references编译指令,但在包体中的authorcount函数代码
并不符合指定的约束,包体中定义的变量v_num不仅仅被该函数读出(不满足rnps约束),而且被修改(不满足wnps约束),
所以plsql引擎编译到函数authorcount是,会报“pls-00452”的错误。

注意事项:
(1)、plsql编译程序根据编译指令来确认包函数的基本约束,从而确认这个包函数是否能在sql语句中使用。
只要随后修改了包体(或第一次创建),就要按照编译指令校检函数代码。
(2)、包初始化部分的代码同样也可以有基础约束。包的基本约束也用restrict_references来指定,
但应以包名为参数而不是以函数名为参数。
(3)、restrict_references可在包中函数定义后的任何位置出现,但它只能约束一个函数的定义。
因此,对于函数的重载,pragma只约束最近定义的函数。
(4)、如果函数中用到了系统包,则该函数不能用在sql语句中。常见系统包dbms_output,dbms_pipe,dbms_alter,dbms_sql,utl_file等。
(5)、当过程性语句中调用一个函数时,可以使用参数缺省值,而通过sql语句调用一个函数时,所有的参数都必须指定。
另外必须使用位置表示法,而不能使用名称表示法。

Oracle Package的更多相关文章

  1. Oracle Package的全局变量与Session

    Oracle Package的全局变量与Session2012-07-26 aaie_ 阅 3595 转 10简单讲,同一个session下pageckage中的全局变量时公共的,会导致冲突.以下是一 ...

  2. C#/java 执行oracle package

    使用pl/sql创建package CREATE OR REPLACE PACKAGE FirstPage is type outlist is ref cursor; Procedure p_get ...

  3. Oracle package demo 包

    1.package 程序包说明(由函数.过程.变量.常量.游标和异常组成) create or replace package pk_test is -- Author : CHEN -- Creat ...

  4. ORACLE PACKAGE中查看包的依赖关系

    SELECT dd.* FROM dba_dependencies dd WHERE NAME <> referenced_name AND referenced_type <> ...

  5. oracle package pragma SERIALLY_REUSABLE(编译指示 告诉PL/SQL 的运行时引擎,在数据引用之时不要保持包级数据。)

    当包第一次被动调用时,将进行初始化:比如将包从硬盘上调到内存中来,放到系统全局工作区的共享缓冲池中,包的运行状态则被放到用户全局区的会话中存储区中,因此可以保证每个调用包的会话都拥有包的运行副本,当会 ...

  6. Oracle中 Package与Package body的介绍

    1.Oracle Package的作用: 可以简化应用设计.提高应用性能.实现信息隐藏.子程序重载 2.ORACLE中的function   .package.package   bodies.pro ...

  7. csharp: ODP.NET,System.Data.OracleClient(.net 4.0) and System.Data.OleDb读取Oracle g 11.2.0的区别

    ODP.NET: 引用: using Oracle.DataAccess; //Oracle g 11.2.0 using Oracle.DataAccess.Client; using Oracle ...

  8. JDBC链接oracle已经mysql的测试

    1.链接oracle package cn.itcast.mybatis.dao; import java.sql.Connection;import java.sql.DriverManager;i ...

  9. oracle 笔记

    1.Oracle认证,与其它数据库比较,安装 Oracle安装会自动的生成sys用户和system用户: (1)sys用户是超级用户,具有最高权限,具有sysdba角色,有create databas ...

随机推荐

  1. Python变量和基本数据类型

    1.变量 a .什么是变量 变量即变化的量,核心是“变”与“量”二字,变即变化,量即衡量状态. b.为什么要有变量 程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制能 ...

  2. 【我的Android进阶之旅】如何去除ListView中Header View、Footer View中的分割线

    最近的项目中给ListView 加入了一个Header View之后,发现Header View的下方也有了分割线,很难看,UI要求将Header View的分割器去掉,好吧.现在就来说一说如何如何去 ...

  3. django 单元测试小结

    测试的场景 框架Django1.8 测试工具 unittest, 要记得给test设置一个独特的settings. 测试请求 也就是测试整个view部分 官方案例 其中可能会遇到登录,或者时sessi ...

  4. (转)java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  5. php imagemagick库安装使用

    imagemagick介绍: ImageMagick® is a software suite to create, edit, compose, or convert bitmap images. ...

  6. hibernatetemplate find条件查询方法

    一.find(String queryString); 示例:this.getHibernateTemplate().find("from bean.User"); 返回所有Use ...

  7. PAT 天梯赛 L1-035. 情人节 【水】

    题目链接 https://www.patest.cn/contests/gplt/L1-035 AC代码 #include <iostream> #include <cstdio&g ...

  8. Spark机器学习6·聚类模型(spark-shell)

    K-均值(K-mean)聚类 目的:最小化所有类簇中的方差之和 类簇内方差和(WCSS,within cluster sum of squared errors) fuzzy K-means 层次聚类 ...

  9. Windows:FTP命令大全

    Windows:FTP命令大全 简介 1, open:与服务器相连接: 2, send(put):上传文件: 3,get:下载文件: 4,mget:下载多个文件: 用法: mget *:下载当前路径下 ...

  10. JAVA基础补漏--内部类

    成员内部类 public class InnerClass { public static void main(String[] args) { System.out.println("++ ...