oracle

关注公众号 jb51net

关闭
首页 > 数据库 > oracle > Oracle包头与包体

Oracle中包的包头与包体用法示例详解

作者:雷神乐乐

在oracle数据库开发中,包(package)是一种将相关过程,函数,变量和游标等对象组织在一起的数据库对象,这篇文章主要介绍了Oracle中包头与包体用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

1.包相关概念介绍 

包就是把相关的存储过程、函数、变量、常量和游标等PL/SQL程序组合在一起,并赋予一定的管理功能的程序块。

包:由包头 + 包体组成

包头相当于是 目录;

包体相当于是 内容;

包头名和包体名必须一致!

创建完包头包体之后,我们就可以将 存储过程&自定义函数 封装到包里面去。

2.创建包和包体的具体步骤

1.将 程序块的 CREATE OR REPLACE 去掉,放到 包体里面;

2.将程序块  IS 之前的内容 放到 包头,作为一个目录;

3.编译(最好 用PL/SQL 美化器,美化一下,然后再编译)  ,点击执行按钮

4.调用

  包里面存储过程调用:

BEGIN
包名.存储过程名称(入参);    
END;

 包里面自定义函数调用:

SELECT 包名.自定义函数名称(入参) FROM 表;

3.创建包头的语法结构

CREATE OR REPLACE PACKAGE PK_TEST1 --- 包名 不区分包头名和包体名,只有一个包名
IS
    PROCEDURE SP_NAME1; --存储过程:PROCEDURE 存储过程名
    PROCEDURE SP_NAME2(P_1 IN NUMBER ....) ; ---可以写多个存储过程

    FUNCTION FUN_NAME1 --自定义函数: FUNCTION 函数名
        RETURN 数据类型; -- 返回一个数据类型 这一句不要忘了

    FUNCTION FUN_NAME2(P_1 IN NUMBER) ---可以写多个函数
        RETURN 数据类型;
END; 

4.创建包体的语法结构

CREATE OR REPLACE PACKAGE BODY PK_TEST1 --包名
IS
    PROCEDURE SP_NAME1 --- 跟包头里面定义的 存储过程名 一致
        IS
    BEGIN
        ......
    END ;


    PROCEDURE SP_NAME2(P_1 IN NUMBER ....)
        IS
    BEGIN
        ......
    END ;

    FUNCTION FUN_NAME1
        RETURN 数据类型
        IS
    BEGIN
        ......
    END FUN_NAME1;

    FUNCTION FUN_NAME2(P_1 IN NUMBER)
        RETURN 数据类型
        IS
    BEGIN
        ......
    END FUN_NAME2;
END; 

5.创建包头和包体练习

5.1练习1

创建包头:

CREATE OR REPLACE PACKAGE PK_0607 --- 包名
 IS
  procedure p_10(P_EMPNO number);

  function P_MAX_MIN(M NUMBER, N NUMBER) return number;
END;

创建包体:

CREATE OR REPLACE PACKAGE BODY PK_0607 --包名
 IS
  procedure p_10(P_EMPNO number) as
    V_JOB varchar2(10); -- 定义变量
    cursor c1 is -- 定义游标
      select * from EMP where JOB = V_JOB;
  begin
    select JOB into V_JOB from EMP where EMPNO = P_EMPNO;
    FOR I IN c1 LOOP
      INSERT INTO EMP_0317
      VALUES
        (i.empno,
         i.ename,
         i.job,
         i.mgr,
         i.hiredate,
         i.sal,
         i.comm,
         i.deptno);
      COMMIT;
    end loop;
  end;

  function P_MAX_MIN(M NUMBER, N NUMBER) return number IS
    temp number;
  BEGIN
    if M > N THEN
      temp := M;
    else
      temp := N;
    end if;
    return temp;
  END;
END;

调用包体中的存储过程:

begin
  PK_0607.p_10(7788);
end;

select * from EMP_0317;

调用包体中的自定义函数

select PK_0607.P_MAX_MIN(3, 1) from dual;

5.2练习2

开发一个包P_TEST_PKG,里面封装两个存储过程,一个自定义函数

1.存储过程A 有入参 P_EMPNO将 EMP表 中 P_EMPNO对应部门的 所有员工同步到 emp_1134;

2.存储过程B,全量同步DEPT 到DEPT_1134;

3.自定义函数 实现一个功能,返回 入参 P_EMPNO 的薪资,自定义异常,如果员工不存在,则返回0;

4.创建包 + 验证。

(1)存储过程A 有入参 P_EMPNO将 EMP表 中 P_EMPNO对应部门的 所有员工同步到 emp_1134; 

建表:

drop table emp_1134;
CREATE TABLE emp_1134 AS SELECT * FROM emp WHERE 1=2;

创建存储过程: 

create or replace procedure P_A(P_EMPNO number) as
  v_source varchar2(20);
  v_target varchar2(20);
  v_st     date;
  v_dt     date;
  v_ct     number := 0;
  V_JOB    varchar2(10); -- 定义变量
  cursor c1 is -- 定义游标
    select * from EMP where JOB = V_JOB;
begin
  v_st     := sysdate;
  v_source := 'emp';
  v_target := 'emp_1134';
  select JOB into V_JOB from EMP where EMPNO = P_EMPNO;
  FOR I IN c1 LOOP
    INSERT INTO emp_1134
    VALUES
      (i.empno, i.ename, i.job, i.mgr, i.hiredate, i.sal, i.comm, i.deptno);
    COMMIT;
    v_ct := v_ct + 1; -- 每次插入后递增计数器 
  end loop;
  v_dt := sysdate;

  -- 调用日志表存储过程
  p_log(p_source_table_name => v_source,
        p_target_table_name => v_target,
        p_step_name         => v_source || ' to ' || v_target,
        p_ROW_COUNT         => v_ct,
        p_status            => '成功',
        p_start_dt          => v_st,
        p_end_dt            => v_dt,
        p_mark              => '');
  -- 定义异常
exception
  when others then
    p_log(p_source_table_name => v_source,
          p_target_table_name => v_target,
          p_step_name         => v_source || ' to ' || v_target,
          p_ROW_COUNT         => 0,
          p_status            => '失败',
          p_start_dt          => v_st,
          p_end_dt            => null,
          p_mark              => SQLERRM);
end;

调用存储过程: 

BEGIN
  P_A(P_EMPNO=>7788);
END;

SELECT * FROM emp_1134;

SELECT * FROM LOG_TABLE;

(2)存储过程B,全量同步DEPT 到DEPT_1134;

建表: 

DROP TABLE dept_1134;
CREATE TABLE dept_1134 AS SELECT * FROM dept WHERE 1=2;

创建存储过程:

create or replace procedure P_B as
  v_source varchar2(20);
  v_target varchar2(20);
  v_st     date;
  v_dt     date;
  v_ct     number := 0;
begin
  v_st     := sysdate;
  v_source := 'DEPT';
  v_target := 'DEPT_1134';
  INSERT INTO DEPT_1134
    SELECT * FROM DEPT;
  v_ct := SQL%ROWCOUNT;
  commit;
  v_dt := sysdate;
  -- 调用日志表存储过程
  p_log(p_source_table_name => v_source,
        p_target_table_name => v_target,
        p_step_name         => v_source || ' to ' || v_target,
        p_ROW_COUNT         => v_ct,
        p_status            => '成功',
        p_start_dt          => v_st,
        p_end_dt            => v_dt,
        p_mark              => '');
  -- 定义异常
exception
  when others then
    p_log(p_source_table_name => v_source,
          p_target_table_name => v_target,
          p_step_name         => v_source || ' to ' || v_target,
          p_ROW_COUNT         => 0,
          p_status            => '失败',
          p_start_dt          => v_st,
          p_end_dt            => null,
          p_mark              => SQLERRM);
end;

调用存储过程:

BEGIN
  P_B;
END;

SELECT * FROM DEPT_1134;

SELECT * FROM LOG_TABLE;

(3)自定义函数 实现一个功能,返回 入参 P_EMPNO 的薪资,自定义异常,如果员工不存在,则返回0;

CREATE OR REPLACE FUNCTION F_SAL(P_EMPNO NUMBER) RETURN NUMBER AS
  V_SAL         NUMBER;
  EMP_NOT_FOUND EXCEPTION;
BEGIN
  BEGIN
    SELECT SAL INTO V_SAL FROM EMP WHERE EMPNO = P_EMPNO; -- 执行查询
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      RAISE EMP_NOT_FOUND; -- 关键:手动触发自定义异常
  END;
  RETURN V_SAL;
EXCEPTION
  WHEN EMP_NOT_FOUND THEN
    -- 现在能捕获到自定义异常
    RETURN 0;
END;

SELECT F_SAL(7788),F_SAL(778) FROM DUAL;

创建包头:

CREATE OR REPLACE PACKAGE P_TEST_PKG 
 IS
  procedure P_A(P_EMPNO number); -- 1.
  procedure P_B;
  function F_SAL(P_EMPNO number) return NUMBER;
END;

创建包体:

CREATE OR REPLACE PACKAGE BODY P_TEST_PKG --包名
 IS
  ------------ procedure P_A
  procedure P_A(P_EMPNO number) as
    v_source varchar2(20);
    v_target varchar2(20);
    v_st     date;
    v_dt     date;
    v_ct     number := 0;
    V_JOB    varchar2(10); -- 定义变量
    cursor c1 is -- 定义游标
      select * from EMP where JOB = V_JOB;
  begin
    v_st     := sysdate;
    v_source := 'emp';
    v_target := 'emp_1134';
    select JOB into V_JOB from EMP where EMPNO = P_EMPNO;
    FOR I IN c1 LOOP
      INSERT INTO emp_1134
      VALUES
        (i.empno,
         i.ename,
         i.job,
         i.mgr,
         i.hiredate,
         i.sal,
         i.comm,
         i.deptno);
      COMMIT;
      v_ct := v_ct + 1; -- 每次插入后递增计数器 
    end loop;
    v_dt := sysdate;
  
    -- 调用日志表存储过程
    p_log(p_source_table_name => v_source,
          p_target_table_name => v_target,
          p_step_name         => v_source || ' to ' || v_target,
          p_ROW_COUNT         => v_ct,
          p_status            => '成功',
          p_start_dt          => v_st,
          p_end_dt            => v_dt,
          p_mark              => '');
    -- 定义异常
  exception
    when others then
      p_log(p_source_table_name => v_source,
            p_target_table_name => v_target,
            p_step_name         => v_source || ' to ' || v_target,
            p_ROW_COUNT         => 0,
            p_status            => '失败',
            p_start_dt          => v_st,
            p_end_dt            => null,
            p_mark              => SQLERRM);
  end;

  ------------ procedure P_B
  procedure P_B as
    v_source varchar2(20);
    v_target varchar2(20);
    v_st     date;
    v_dt     date;
    v_ct     number := 0;
  begin
    v_st     := sysdate;
    v_source := 'DEPT';
    v_target := 'DEPT_1134';
    INSERT INTO DEPT_1134
      SELECT * FROM DEPT;
    v_ct := SQL%ROWCOUNT;
    commit;
    v_dt := sysdate;
    -- 调用日志表存储过程
    p_log(p_source_table_name => v_source,
          p_target_table_name => v_target,
          p_step_name         => v_source || ' to ' || v_target,
          p_ROW_COUNT         => v_ct,
          p_status            => '成功',
          p_start_dt          => v_st,
          p_end_dt            => v_dt,
          p_mark              => '');
    -- 定义异常
  exception
    when others then
      p_log(p_source_table_name => v_source,
            p_target_table_name => v_target,
            p_step_name         => v_source || ' to ' || v_target,
            p_ROW_COUNT         => 0,
            p_status            => '失败',
            p_start_dt          => v_st,
            p_end_dt            => null,
            p_mark              => SQLERRM);
  end;

  ------------ function F_SAL(P_EMPNO number)
  FUNCTION F_SAL(P_EMPNO NUMBER) RETURN NUMBER AS
    V_SAL         NUMBER;
    EMP_NOT_FOUND EXCEPTION;
  BEGIN
    BEGIN
      SELECT SAL INTO V_SAL FROM EMP WHERE EMPNO = P_EMPNO; -- 执行查询
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        RAISE EMP_NOT_FOUND; -- 关键:手动触发自定义异常
    END;
    RETURN V_SAL;
  EXCEPTION
    WHEN EMP_NOT_FOUND THEN
      -- 现在能捕获到自定义异常
      RETURN 0;
  END;
END;

清空相关表: 

TRUNCATE TABLE DEPT_1134;
TRUNCATE TABLE emp_1134;
TRUNCATE TABLE LOG_TABLE;

调用第一个存储过程:

BEGIN
  P_TEST_PKG.P_A(7788);
END;

SELECT * FROM emp_1134;

调用第二个存储过程:

BEGIN
  P_TEST_PKG.P_B;
END;

SELECT * FROM DEPT_1134;

查询日志表:

SELECT * FROM LOG_TABLE;

调用自定函数: 

SELECT P_TEST_PKG.F_SAL(7369),P_TEST_PKG.F_SAL(778) FROM DUAL;

6.存储过程和自定义函数区别

1.函数必须要有返回值,函数里面不能调用存储过程

2.存储过程里面可以调用自定义函数,可以调用存储过程,存储过程不需要返回值

总结 

到此这篇关于Oracle中包头与包体用法的文章就介绍到这了,更多相关Oracle包头与包体内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文