CREATE PACKAGE
定义一个包。CREATE OR REPLACE PACKAGE
将会创建一个新包或者替换一个已有的定义。包是组织和封装数据库应用程序逻辑的重要工具。通过合理设计和使用包,可以提高代码的可维护性、重用性和性能。
简介
CREATE PACKAGE语句用于创建存储包的规范,存储包是存储在数据库中的相关过程、函数及其他程序对象的封装集合。包规范声明了这些对象,而随后的包体则定义了这些对象的具体实现。
如果创建包时包含schema
名称,则将在指定的schema
中创建。否则,将在当前schema
中创建。除非要更新现有包的定义,否则新包的名称不能与同一schema
中的任何现有包匹配。在这种情况下,请使用CREATE OR REPLACE PACKAGE
。创建该过程的用户将成为包的所有者。
包是将过程和函数创建为独立模块对象的替代方案。
语法
CREATE [ OR REPLACE ] PACKAGE <package_name>
[ AUTHID { DEFINER | CURRENT_USER } ]
{ IS | AS }
[ <declaration>; ] [, ...]
[ {
PROCEDURE <proc_name>
[ (<argname> [ IN | IN OUT | OUT ] <argtype> [ DEFAULT <value> ]
[, ...]) ];
[ PRAGMA RESTRICT_REFERENCES(<proc_name>,
{ RNDS | RNPS | TRUST | WNDS | WNPS } [, ... ] ); ]
|
FUNCTION <func_name>
[ (<argname> [ IN | IN OUT | OUT ] <argtype> [ DEFAULT <value> ]
[, ...]) ]
RETURN <rettype> [ DETERMINISTIC ];
[ PRAGMA RESTRICT_REFERENCES(<func_name>,
{ RNDS | RNPS | TRUST | WNDS | WNPS } [, ... ] ); ]
}
] [, ...]
END [ <name> ]
参数说明
参数 | 描述 |
package_name | 要创建的包的名称(可选 |
DEFINER | CURRENT_USER | 指定使用何种权限访问包中引用的数据库对象。取值范围如下:
|
declaration | 公共变量、类型、游标或 |
proc_name | 公共存储过程名称。 |
argname | 参数名称。 |
IN | IN OUT | OUT | 参数模式。 |
argtype | 程序参数的数据类型。 |
DEFAULT value | 输入参数的默认值。 |
func_name | 公共函数名称。 |
rettype | 返回数据类型。 |
DEFERMININTIC |
|
RNDS | RNPS | TRUST | WNDS | WNPS | 为实现兼容性提供该参数,请忽略。 |
结构
包头定义了包的接口部分,包括公开的常量、变量、类型、过程和函数等。其他程序单元可以引用包头中声明的对象。
CREATE OR REPLACE PACKAGE Employee_Pkg AS
-- 常量
MAX_SALARY CONSTANT NUMBER := 100000;
-- 过程声明
PROCEDURE Add_Employee(
p_emp_id IN NUMBER,
p_first_name IN VARCHAR2,
p_last_name IN VARCHAR2,
p_salary IN NUMBER
);
PROCEDURE Update_Salary(
p_emp_id IN NUMBER,
p_new_salary IN NUMBER
);
-- 函数声明
FUNCTION Get_Employee_Name(
p_emp_id IN NUMBER
) RETURN VARCHAR2;
END Employee_Pkg;
注意事项
依赖管理:修改包头会导致依赖包的所有对象需要重新编译,请谨慎进行变更。
错误处理:在包中妥善处理异常,避免未捕获的异常导致程序中断。
性能优化:合理使用包的私有变量和缓存机制,提高性能。
安全性:通过包的权限控制限制对敏感数据和功能的访问。
命名规范:遵循统一的命名规范,便于代码理解和维护。
使用说明
一旦包成功创建并编译完成,即可在PL/SQL代码中引用包内的过程、函数等。
调用包中的过程和函数
调用过程。
BEGIN Employee_Pkg.Add_Employee( p_emp_id => 1001, p_first_name => '张', p_last_name => '三', p_salary => 50000 ); END;
调用函数
DECLARE v_emp_name VARCHAR2(100); BEGIN v_emp_name := Employee_Pkg.Get_Employee_Name(1001); DBMS_OUTPUT.PUT_LINE('员工姓名: ' || v_emp_name); END;
包同名函数处理
Oracle支持包中的同名函数,实现类似多态的行为,对应的PolarDB也支持相同的行为。
PolarDB PostgreSQL版Oracle语法兼容 2.0在内核小版本2.0.14.26.0新增创建IN参数相同,OUT参数不同的同名函数。若集群的内核小版本低于该版本且需要使用该功能,请将内核小版本升级到2.0.14.26.0或以上版本。查询和升级内核小版本,请参见版本管理。
CREATE OR REPLACE PACKAGE Employee_Pkg AS
-- 常量
MAX_SALARY CONSTANT NUMBER := 100000;
-- 函数声明
FUNCTION Get_Employee_Name(
p_emp_id IN NUMBER
) RETURN VARCHAR2;
-- 同名函数
FUNCTION Get_Employee_Name(
p_emp_id IN NUMBER,
res_info OUT text
) RETURN VARCHAR2;
END Employee_Pkg;
包函数使用包变量作为参数默认值
PolarDB PostgreSQL版Oracle语法兼容 2.0在内核小版本2.0.14.26.0新增使用包变量做函数参数默认值。若集群的内核小版本低于该版本且需要使用该功能,请将内核小版本升级到2.0.14.26.0或以上版本。查询和升级内核小版本,请参见版本管理。
CREATE OR REPLACE PACKAGE test_package AS
a NUMBER := 1;
b NUMBER := 2;
END my_package;
CREATE OR REPLACE PACKAGE my_package AS
FUNCTION add_numbers(x NUMBER default test_package.a, y NUMBER default test_package.b) RETURN NUMBER;
PROCEDURE print_message(msg VARCHAR2);
END my_package;
维护和更新包
如需向包中添加新的公开对象,必须对包头和包体进行相应的修改。修改包头将导致依赖该包的所有对象失效,需要重新进行编译。如果仅对包体中的实现进行修改(不影响包头),则无需重新编译依赖对象。详细的包体SQL语句介绍请参考CREATE PACKAGE BODY。
向包中添加新函数。
修改包头。
CREATE OR REPLACE PACKAGE Employee_Pkg AS -- 现有声明 FUNCTION Get_Employee_Department(p_emp_id IN NUMBER) RETURN VARCHAR2; END Employee_Pkg;
修改包体。
CREATE OR REPLACE PACKAGE BODY Employee_Pkg AS -- 现有实现 FUNCTION Get_Employee_Department(p_emp_id IN NUMBER) RETURN VARCHAR2 IS v_department VARCHAR2(100); BEGIN SELECT department INTO v_department FROM employees WHERE emp_id = p_emp_id; RETURN v_department; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 'Not Assigned'; END Get_Employee_Department; END Employee_Pkg;
相关参考
完整的包创建和使用示例请参考示例。