练习 1:
--创建package header
CREATE OR REPLACE PACKAGE emp_pack 
IS
  PROCEDURE new_emp
    (v_ename   emp.ename%TYPE,
     v_job     emp.job%TYPE     DEFAULT 'SALESMAN',
     v_mgr     emp.mgr%TYPE     DEFAULT 7839, 
     v_sal     emp.sal%TYPE     DEFAULT 1000,
     v_comm    emp.comm%TYPE    DEFAULT 0,
     v_deptno  emp.deptno%TYPE  DEFAULT 30);
END emp_pack;
/

--创建package body
CREATE OR REPLACE PACKAGE BODY emp_pack 
IS
  FUNCTION valid_deptno --私有函数
    (v_deptno IN dept.deptno%TYPE)
    RETURN BOOLEAN
  IS 
    v_dummy  VARCHAR2(1);
  BEGIN
    SELECT 'x'
    INTO   v_dummy
    FROM   dept
    WHERE  deptno = v_deptno;
    RETURN (TRUE);
  EXCEPTION
    WHEN NO_DATA_FOUND THEN 
      RETURN(FALSE);
  END valid_deptno;

  PROCEDURE new_emp
    (v_ename   emp.ename%TYPE,
     v_job     emp.job%TYPE     DEFAULT 'SALESMAN',
     v_mgr     emp.mgr%TYPE     DEFAULT 7839,
     v_sal     emp.sal%TYPE     DEFAULT 1000,
     v_comm    emp.comm%TYPE    DEFAULT 0,
     v_deptno  emp.deptno%TYPE  DEFAULT 30)
  IS
  BEGIN
    IF valid_deptno(v_deptno) THEN
      INSERT INTO emp
      VALUES (seq_empno.NEXTVAL, v_ename, v_job, v_mgr, 
              TRUNC (SYSDATE, 'DD'), v_sal, v_comm, v_deptno);
    ELSE
      DBMS_OUTPUT.PUT_LINE('Invalid department number. Try again.');
    END IF;
  END new_emp;
END emp_pack;
/
****
HR@prod> l
  1  create or replace package pack_sal
  2  is
  3      procedure add_sal (v_id in employees.employee_id%type,v_raise_sal in number);
  4      function get_tax(v_id in employees.employee_id%type) return number;
  5* end pack_sal;
HR@prod> /

Package created.

HR@prod> get pack_body.sql
  1  create or replace package body pack_sal
  2  is
  3      procedure add_sal(v_id in employees.employee_id%type,
  4                        v_raise_sal in number)
  5      is
  6      begin
  7           update employees set salary=salary+ v_raise_sal
  8           where employee_id=v_id;
  9      end add_sal;
 10      function get_tax(v_id in employees.employee_id%type)
 11      return number
 12      is
 13          v_sal  number;
 14          v_tax  number;
 15      begin
 16          select salary into v_sal from employees
 17          where employee_id=v_id;
 18          if v_sal >= 5000 then
 19             v_tax := (v_sal - 5000)*0.2;
 20             return v_tax;
 21          else
 22             return v_sal*0.1;
 23          end if;
 24      end get_tax;
 25* end;
HR@prod> /

Package body created.

HR@prod> desc pack_sal;
PROCEDURE ADD_SAL
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 V_ID                           NUMBER(6)               IN
 V_RAISE_SAL                    NUMBER                  IN
FUNCTION GET_TAX RETURNS NUMBER
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 V_ID                           NUMBER(6)               IN

HR@prod> select salary from employees where employee_id=100;

    SALARY
----------
     26400

HR@prod> exec pack_sal.add_sal(100,600);

PL/SQL procedure successfully completed.

HR@prod> select salary from employees where employee_id=100;

    SALARY
----------
     27000

HR@prod> select pack_sal.get_tax(100) from dual;

PACK_SAL.GET_TAX(100)
---------------------
                 4400

----------------------------------------------------------------------
练习 2:重载
--创建package header
CREATE OR REPLACE PACKAGE over_load is
  FUNCTION print_it(v_arg date)
    RETURN VARCHAR2;
  FUNCTION print_it(v_arg NUMBER)
    RETURN VARCHAR2;
END over_load;
/

--创建package body
CREATE OR REPLACE PACKAGE BODY over_load is
  FUNCTION print_it(v_arg date)
    RETURN VARCHAR2
  IS
  BEGIN
    RETURN to_char(v_arg,'yyyy-mm-dd');
  END print_it;

  FUNCTION print_it(v_arg NUMBER) -----此处应该是NUMBER类型
    RETURN VARCHAR2
  IS
  BEGIN
    RETURN to_char(v_arg,'L99,999.00');  //L--->$
  END print_it;
END over_load;
/

--包的调用
VARIABLE g_datevalue varchar2(40);
execute :g_datevalue := over_load.PRINT_IT(sysdate); 
print g_datevalue

VARIABLE g_datevalue varchar2(40);
execute :g_datevalue := over_load.PRINT_IT(123); 
print g_datevalue

select over_load.print_it(123)  from dual;
select over_load.print_it(to_date('2013-11-19','yyyy-mm-dd'));
************************************************************************
SYS@prod> get pack1.sql
  1  create or replace package over_load
  2  is
  3      function print_strings(v_date date) return VARCHAR2;
  4      function print_strings(v_number number) return VARCHAR2;
  5* end over_load;
SYS@prod> /

Package created.

SYS@prod> get pack2.sql
  1  create or replace package body over_load
  2  is
  3      function print_strings(v_date date) return VARCHAR2
  4      is
  5      begin
  6           return to_char(v_date,'yyyy-mm-dd hh24:mi:ss');
  7      end print_strings;
  8      function print_strings(v_number number) RETURN VARCHAR2
  9      is
 10      begin
 11           return to_char(v_number,'L99,999,999,999.99');
 12      end print_strings;
 13* end over_load;
SYS@prod> /

Package body created.

SYS@prod> desc over_load;
FUNCTION PRINT_STRINGS RETURNS VARCHAR2
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 V_DATE                         DATE                    IN
FUNCTION PRINT_STRINGS RETURNS VARCHAR2
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 V_NUMBER                       NUMBER                  IN

SYS@prod> select over_load.print_strings(sysdate) from dual;

OVER_LOAD.PRINT_STRINGS(SYSDATE)
--------------------------------------------------------------------------------
2012-12-28 10:45:42

SYS@prod> select over_load.print_strings(123456789) from dual;

OVER_LOAD.PRINT_STRINGS(123456789)
--------------------------------------------------------------------------------
             $123,456,789.00


----------------------------------------------------------------------
包与依赖:断开了依赖链
DROP TABLE T;
create table t (x int);

create view v as select * from t;

create procedure p
is
begin
 for x in (select * from v)
 loop
  null;
 end loop;
end;
/

create function f return number
is
 l_cnt number;
begin
 select count(*) into l_cnt from t;
 return l_cnt;
end;
/

查看依赖关系:

select name,type,referenced_name,referenced_type
from user_DEPENDENCIES
where name IN ('F','P','T','V')
AND referenced_owner='SCOTT'
order by name;

查看对象有效状态:

select object_name,object_type,status 
from user_objects
where object_name in ('F','P','T','V');

修改T表结构后,再看有效性:

alter table t add y number;

select object_name,object_type,status 
from user_objects
where object_name in ('F','P','T','V');

V P F 无效

创建一个依赖P的过程后,再看有效性:
create procedure p2 
is
begin
p;
end;
/

select object_name,object_type,status 
from user_objects
where object_name in ('F','P','P2','T','V');

V P 重新有效!对P2的编译同时重新编译了V P!

使用包重做上面的实验:

create package pk1
is
 procedure p;
end;
/

create package body pk1
is
procedure p
is
begin
 for x in (select * from v)
 loop
  null;
 end loop;
end;
end pk1;
/

create package pk2
is
 procedure p;
end;
/

create package body pk2
is
procedure p
is
begin
 pk1.p;
end;
end pk2;
/

select object_name,object_type,status 
from user_objects
where object_name in ('F','P','P2','T','V','PK1','PK2');

再次修改T,再查看有效性!PK1 包体无效了!因为PK1 包体通过V依赖与T(依赖链)
而PK2仍然有效!PK2依赖与PK1而不是PK1包体(因而断开了依赖链)!

exec pk2.p;

select object_name,object_type,status 
from user_objects
where object_name in ('F','P','P2','T','V','PK1','PK2');
-------------------------------------------------------------------------------