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包头与包体内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Oracle中实现类似于Mysql中的Field()函数功能
这篇文章主要详细介绍了在Oracle中如何实现类似于Mysql中的Field()函数功能,本文主要通过代码示例介绍了Oracle中的Decode()函数和Oracle中的row_number,需要的朋友可以参考下2023-06-06
linux系统oracle数据库出现ora12505问题的解决方法
这篇文章主要介绍了linux系统oracle数据库出现ora12505问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2016-12-12
Oracle查询中OVER (PARTITION BY ..)用法
这篇文章主要介绍了Oracle查询中OVER (PARTITION BY ..)用法,内容和代码大家参考一下。2017-11-11


最新评论