`

Oracle_PL_ SQL_ 教程:包

 
阅读更多
--######################################--
--包
--王林 2012.07.06
--######################################--

/*
包可以将一些有联系的对象放在其内部。任何能在块定义部分出现的对象都可以在包中出现。这些对象包括存储过程、函数、游标、自定义的类型和变量。可以在其他的块中引用包中的这些对象,因此,包提供了全局变量。一个包由两个独立的部分组成--包头和包体。各部分被单独地存放在数据字典中。定义一个包,要分别定义包头和包体。存储过程或者函数必须在包头中预定义。即在包头中仅定义存储过程或函数以及他们的参数,存储过程或函数的执行代码将在包体中定义。
这不同于无名块中定义存储过程和函数。包体是一个数据字典对象。只有在包头成功编译后,包体才能被编译。包体只包含包头中已预定义的子程序的代码。在包头中定义的对象(不是预定义的)的对象可以直接在包体中使用,不必在包体中定义。如果在包头中有预定义的子程序,则在包体中必须编写其子程序代码,而且包头和包体两部分的子程序必须一致,这包括相同的子程序名、参数和参数类型。与变量类似,包也可以被初始化。只是初始化部分定义在包体的最后部分被定义。
*/

--######################################--
--前向引用
--前向引用占位程序让PL/SQL单遍分析器将过程B的声明放在他的标识符列表中
--JAVA采用的是双遍分析器,所以不用前向声明
DECLARE 
    --如果将过程B的前向引用去掉,程序引发ORA-00313错误
    --因为单遍分析器是自上向下读取的,在分析器读取过程B之前添加B的声明。
    --当分析器读取过程A时,他知道有过程B的声明,然后分析器对过程A的调用验证有效性,以后再在程序中查找B的实现,从而编译成功。
    PROCEDURE b (caller VARCHAR2);
    PROCEDURE a (caller VARCHAR2)
    IS
        procedure_name VARCHAR2 (1) := 'A';
    BEGIN
        DBMS_OUTPUT.put_line( 'Procedure ''a'' called by ['
                            || caller
                            || '].');
        b(procedure_name);
    END;
    PROCEDURE b (caller VARCHAR2)
    IS
        procedure_name VARCHAR2 (1) := 'B';
    BEGIN
        DBMS_OUTPUT.put_line( 'Procedure ''b'' called by ['
                            || caller
                            || '].');
    END;
BEGIN
    a( 'Main' );
END;
--执行结果:
Procedure 'a' called by [Main].
Procedure 'b' called by [A].

--######################################--
--包头 | 包规范原型
--包规范原型列出的所有组件都是可选的,因为没有任何组件也可以创建包
--在包头声明过的是外部可以调用的过程、函数、变量
--包头是必须的,包体是可选的
--包头必须在包体前创建,否则创建不了包体
CREATE [OR REPLACE] PACKAGE package_name [AUTHID] {DEFINER | CURRENT_USER}
IS | AS
    [type_definition;]
    [procedure_specification;]
    [function_specification;]
    [variable_declaration;]
    [exception_declaration;]
    [cursor_delaration;]
    [progma_delaration;]
END package_name;

--######################################--
--包体
--包体是一个独立于包头的数据字典对象,包体只能在包头完成编译后才能编译
--包体内部还可以包括具有包体全局属性的附加声明部分,但这些附加说明对于包体外部是不可见的
CREATE [OR REPLACE] PACKAGE package_name 
AS
    --全局变量定义;
    --函数定义;
    --过程定义;
END package_name; 

--######################################--
--创建包头
CREATE OR REPLACE PACKAGE demo_package
IS
    --包含了一个公用的过程和变量
    g_comm NUMBER := 0.10;
    PROCEDURE reset_comm(p_comm IN NUMBER);
    --注释掉也可以,但是在外部不能调用该函数
    /*FUNCTION validate_comm(p_comm IN NUMBER)
        RETURN BOOLEAN;*/
END;
--创建包体
CREATE OR REPLACE PACKAGE BODY demo_package
IS
    FUNCTION validate_comm(p_comm IN NUMBER)
        RETURN BOOLEAN
    IS
        v_max_comm NUMBER;
    BEGIN
        SELECT MAX(a.empno) 
          INTO v_max_comm
          FROM scott.emp a;
        IF (p_comm > v_max_comm) THEN
            RETURN (FALSE);
        ELSE
            RETURN (TRUE);
        END IF;
    END validate_comm;
    PROCEDURE reset_comm(p_comm IN NUMBER)
    IS
    BEGIN
        IF validate_comm(p_comm) THEN
            g_comm := p_comm;
        ELSE
            raise_application_error(-20210 , 'Expresion is not avilable');
        END IF;
        DBMS_OUTPUT.put_line('This is the globle variable:' || g_comm);
    END reset_comm;
END demo_package;
--SQL Command->编译->执行: 
exec demo_package.reset_comm(0);
--执行结果: 
This is the globle variable:0
--SQL Command->编译->执行:
exec demo_package.reset_comm(999999);
--执行结果: 
begin demo_package.reset_comm(999999); end;
 
ORA-20210: Expresion is not avilable
ORA-06512: at "SYSTEM.DEMO_PACKAGE", line 23
ORA-06512: at line 2

--查看包内的代码
SET pagesize 49999;
COLUMN line format 99999 heading "Line#";
COLUMN text format A73 heading "Text";
SELECT line , text 
  FROM User_Source 
 WHERE UPPER(NAME) = UPPER('&input_name');

--######################################--
--变量
--默认情况下,包是不连续的,当第一个用户调用之后,并不能保证第二个用户调用的仍然是同一个包
--当没有在包规范中声明共享变量或游标时,这个默认情况是很有用的,因为函数和过程是可以重用的。
--当包中含有共享变量时,应总是使包连续可重用
--PRAGMA SERIALLY_REUSABLE (预编译指令)只能在包上下文使用,必须在包规范和主体中都使用它。
--当要共享变量时, PRAGMA SERIALLY_REUSABLE很重要,因为他能保证每次调用他们都处于初始状态。
--E.g:测试共享变量
CREATE OR REPLACE PACKAGE demo_variables
IS
    --把PRAGMA SERIALLY_REUSABLE放在包规范中,将包定义为连续可重用,那么该案例结果永远是3
    --之所以这样,是因为每次对包的调用都会得到一个最新的副本。连续可重用包会重新初始化共享变量的值。
    --常量和连续可重用变量之间的唯一区别是常量的值是永远不能改变,而变量的值是可以改变的
    --当包为连续可重用时,接下来对包的任何调用就不会再改变值
    --包变量应当总是常量
    /*PRAGMA SERIALLY_REUSABLE;*/
    protecte CONSTANT NUMBER := 1;
    unprotecte        NUMBER := 1;
END demo_variables;
--
CREATE OR REPLACE PROCEDURE demo_change(n_value NUMBER)
IS
    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    demo_variables.unprotecte := demo_variables.unprotecte + n_value;
    Dbms_Output.put_line(demo_variables.unprotecte);
END demo_change;
--执行下去依次递增
--SQL Command->编译->执行: 
exec demo_change(2);
--执行结果: 
3

--######################################--
--类型
--%:属性指示器
--%ROWTYPE: 将变量的数据类型锚定到数据库目录对象上或PL/SQL记录结构的行结构上。当锚定到目录对象上时,新变量继承了在引用表或视图中列的位置和数据类型。新变量继承了显式PL/SQL记录结构的位置和数据结构,而该位置和数据类型可能是间接的从一个或多个目录对象继承的。
--%TYPE: 将变量的数据类型锚定到在数据库目录对象(表或视图)中列的数据类型。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics