Oracle PL/SQL : How to implement pointers to in-memory record types

标签 oracle pointers plsql ref

我有两个包裹 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;

方法二——环境包

因为包状态属于一个 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/

相关文章:

sql - 回滚已提交的数据

c++ - 错误 : pointer being freed was not allocated

c++ - 像数组一样对待 std::vector 是否可移植

C++ 变量可见范围和流

oracle - ORA-01741 用于带有不可见字段和隐式约束的 DBMS_REDEFINITION

database - 在 PL/SQL 中使用 "select *"作为游标是否被认为是糟糕的编程?

sql - mysql 触发器到 oracle 触发器

asp.net - ASP 成员(member)资格奇怪的问题

javascript - 如何在 oracle apex 的动态操作中从 PLSQL 代码内部调用 Javascript

sql - 连接太长