我有两个包 pkg_company 和 pkg_employee 。 pkg_company 包括一个(记录)类型定义 typ_company。 pkg_employee 包括一个类型定义 typ_employee。
我有一个公司类型的实例和 1000 个 typ_employee 的实例。在员工类型中,我想要一个指向公司实例的指针。
declare
c pkg_company.typ_company;
e pkg_employee.typ_employee;
begin
c := pkg_company.get(12345);
for e in (select employeeid from employee where companyid=12345)
loop
e := pkg_employee.get(12345, c); -- c passed by reference in out nocopy
pkg_employee.process(e); -- I would like to access company info inside here as e.c.companyname
end loop;
end;
如何在 e 中存储指向 c 的指针?我不想创建 1000 个 c 的副本。只想存储指针并在需要时访问该值。
感谢所有的帮助!
结尾;
最佳答案
在 Oracle SQL
中,use REF
and DEREF
functions 可以将逻辑指针传递给存储在数据库表中的对象。
但是 PL/SQL
中没有指针或引用之类的东西,因此您需要一种解决方法。
下面是 PL/SQL 中可能的解决方法的一些方法。对于代码中的任何错误,我提前道歉。它旨在演示方法而不是用于生产。
方法 1 - 缓存访问方法
通用思想是通过缓存结果的函数访问实体:
create or replace package EntitytAccess as
procedure GetCompany1(
pCompanyId in number,
pCompany out nocopy pkg_company.typ_company
);
function GetCompany2(
pCompanyId in number
) return pkg_company.typ_company;
procedure ClearCompanyCache;
end;
访问包体:
create or replace package body EntitytAccess as
type typ_company_cache is table of pkg_company.typ_company index by number;
var_company_cache typ_company_cache;
procedure GetCompany1(
pCompanyId in number,
pCompany out nocopy pkg_company.typ_company
)
is
begin
if( var_company_cache.exists(pCompanyId) )
pCompany := var_company_cache(pCompanyId);
else
pCompany := pkg_company.get(pCompanyId);
var_company_cache(pCompanyId) := pCompany;
end if;
end;
function GetCompany2(
pCompanyId in number
) return pkg_company.typ_company
is
begin
if(not var_company_cache.exists(pCompanyId) )
var_company_cache(pCompanyId) := pkg_company.get(pCompanyId);
end if;
return var_company_cache(pCompanyId);
end;
procedure ClearCompanyCache
is
begin
var_company_cache.Delete;
end;
end;
用法:
declare
c pkg_company.typ_company;
e pkg_employee.typ_employee;
begin
EntityAccess.GetCompany2(12345,c);
for e in (select employeeid from employee where companyid=12345)
loop
e := pkg_employee.get(12345, c); -- c passed by reference in out nocopy
-- and c.companyid stored inside e.
pkg_employee.process(e); -- No need to pass company, but inside process()
-- method you need to call either
-- EntityAccess.GetCompany1(e.companyid, var_c)
-- or
-- var_c := EntityAccess.GetCompany2(e.companyid)
end loop;
end;
方法 2 - 环境包
因为包状态属于一个 session ,所以您可以使用包变量来保存当前处理状态并在需要时引用它。
create or replace package ProcessEnvironment as
var_current_company pkg_company.typ_company;
-- may be more "global" variables here
end;
/
create or replace package body ProcessEnvironment as
end;
用法:
declare
e pkg_employee.typ_employee;
begin
ProcessEnvironmant.var_current_company := pkg_company.get(12345);
for e in (select employeeid from employee where companyid=12345)
loop
e := pkg_employee.get(12345, ProcessEnvironmant.var_current_company);
-- c passed by reference in out nocopy
-- and c.companyid stored inside e.
pkg_employee.process(e); -- No need to pass company, but inside process()
-- method you references
-- ProcessEnvironmant.var_current_company
-- with appropriate checks
end loop;
end;
混合方法
似乎在从集合复制的
Approach 1
实例的情况下,特别是如果使用函数 GetCompany2()
访问。复制构造函数可能足够快,但会产生一些开销。对于
Approach 2
,业务逻辑函数的代码中必须存在一些检查,因此从另一个角度来看,这是维护开销。要处理这两个问题,您可以使用缓存,但在包中只保存一个值:
create or replace package EntitytAccess as
procedure GetCompany(
pCompanyId in number,
pCompany out nocopy pkg_company.typ_company
);
end;
包体:
create or replace package body EntitytAccess as
var_cached_company pkg_company.typ_company;
procedure GetCompany(
pCompanyId in number,
pCompany out nocopy pkg_company.typ_company
)
is
begin
if( (var_cached_company is null)
or
(var_cached_company.comanyid != pCompanyId)
)then
var_company_cache := pkg_company.get(pCompanyId);
end if;
pCompany := var_cached_company;
end;
end;
用法:
declare
c pkg_company.typ_company;
e pkg_employee.typ_employee;
begin
EntityAccess.GetCompany(12345,c);
for e in (select employeeid from employee where companyid= c.companyid)
loop
e := pkg_employee.get(c.companyid , c); -- c passed by reference in out nocopy
-- and c.companyid stored inside e.
pkg_employee.process(e); -- No need to pass company, but inside process()
-- method you need to call
-- EntityAccess.GetCompany(e.companyid, var_c)
-- where var_c is company object variable.
end loop;
end;
关于Oracle Pl/SQL : How to implement pointers to in-memory record types,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18334673/