【问题标题】:Oracle object dependency loopOracle 对象依赖循环
【发布时间】:2013-09-05 08:08:39
【问题描述】:

当我尝试在 Oracle 数据库中编译我的项目时遇到问题。为了更简单,我有三个对象:2 个包(UTILS 和 TYPES)和 1 个视图(VIEW)。

包 UTILS 使用包 TYPES 中定义的类型。 Package TYPES 使用 VIEW 作为其中一种类型的基础。并且 VIEW 在其脚本中使用包 UTILS 中的函数。当我尝试对这些对象之一进行一些更改时,我无法编译,因为一切都处于无效状态。所以创建了某种对象依赖循环。

请帮我解决这个问题。

例如,有没有编译下面的代码?每个对象在语法上都是正确的,但是如何将它们全部编译在一起呢?

create or replace package my_types is
   type type1 is table of number;
   type type2 is table of my_view%rowtype;
end;
/

create or replace package my_utils is
   function get_1 return number;
   procedure do_something(parameter my_types.type2);
end;
/

create or replace package body my_utils is
   function get_1 return number is
   begin
       return 1;
   end;

   procedure do_something(parameter my_types.type2) is
   begin
       null;
   end;
end;
/

create or replace force view my_view as
select * from dual
where 1 = my_utils.get_1();

exec dbms_utility.compile_schema(user, false);

select object_name from user_objects where status <> 'VALID';

【问题讨论】:

  • 打破循环?使函数的执行成为运行时效果(而不是嵌入到查询中)——例如:从字符串中执行函数。
  • 所以打破循环是解决这个问题的唯一方法吗?我认为在编译包/视图以忽略其依赖项的无效状态时可能会有一些提示。
  • 不知道——你会想要一些 oracle 无所不知的 :-) 我对 Postgres 比较熟悉,这就是我在那里的做法。 (它不会受到 exact 问题的影响,但您仍然可以创建依赖循环)。
  • 唯一明智的方法是打破循环,正如@David-SkyMesh 所建议的那样。请您将代码添加到您的问题中吗?
  • @jonearles - 我相信你已经看过这个,但是UTL_RECOMP 无法直接或通过utlrp 解决它,这很有趣。建议在我认为的这个版本中它是不可解决的,无论如何都不需要拆分。

标签: oracle oracle11g


【解决方案1】:

如果你在两个视图中打破视图,你可以打破循环依赖:

create or replace view my_view_1
as select * from dual; 

create or replace package my_types is
   type type1 is table of number;
   type type2 is table of my_view_1%rowtype;
end;
/

create or replace package my_utils is
   function get_1 return number;
   procedure do_something(parameter my_types.type2);
end;
/

create or replace package body my_utils is
   function get_1 return number is
   begin
       return 1;
   end;

   procedure do_something(parameter my_types.type2) is
   begin
       null;
   end;
end;
/

create or replace view my_view as
select * from my_view_1
where 1 = my_utils.get_1();

编辑:另一种可能性是将包 my_utils 分成两部分:

create or replace package my_utils_1 is
   function get_1 return number;
end;
/
create or replace package body my_utils_1 is
   function get_1 return number is
   begin
       return 1;
   end;
end;
/

create or replace view my_view as
select * from dual
where 1 = my_utils_1.get_1();

create or replace package my_types is
   type type1 is table of number;
   type type2 is table of my_view%rowtype;
end;
/

create or replace package my_utils_2 is
   procedure do_something(parameter my_types.type2);
end;
/
create or replace package body my_utils_2 is
   procedure do_something(parameter my_types.type2) is
   begin
       null;
   end;
end;
/

【讨论】:

  • +1 这是一个可能的解决方案,但对于赏金,我正在寻找更好的解决方案。创建两个视图并不理想,因为它们需要保持同步。在更现实的场景中,如果不重复大量逻辑,视图就无法如此轻松地拆分。
【解决方案2】:

我会避免使用打包类型和 %ROWTYPE。这些不是标准 SQL,可以替换为Structured Types

create or replace view my_view_1
as select * from dual; 

create or replace type type1 as table of number;
create or replace type type2 as object (DUMMY VARCHAR2(1 byte));
create or replace type table_type2 as table of type2;

create or replace package my_utils is
   function get_1 return number;
   procedure do_something(parameter table_type2);
end;
/

create or replace package body my_utils is
   function get_1 return number is
   begin
       return 1;
   end;

   procedure do_something(parameter table_type2) is
   begin
       null;
   end;
end;
/

create or replace view my_view as
select * from my_view_1
where 1 = my_utils.get_1();

【讨论】:

  • 不确定标准 SQL 带来了什么。根据对象类型的使用(我们在这里没有看到),它可能会影响性能......
  • 打包类型和 %ROWTYPE 只能在 PL/SQL 中使用。您不能使用 SQL 查询或视图来选择它们。在性能方面,它们不会有太大不同
【解决方案3】:

如果您不想/不能拆分您的包或视图,您始终可以先创建视图的虚拟版本,编译包,然后创建“真实”视图:

create or replace package my_types is
   type type1 is table of number;
   type type2 is table of my_view%rowtype;
end;
/

create or replace package my_utils is
   function get_1 return number;
   procedure do_something(parameter my_types.type2);
end;
/

create or replace package body my_utils is
   function get_1 return number is
   begin
       return 1;
   end;

   procedure do_something(parameter my_types.type2) is
   begin
       null;
   end;
end;
/

create or replace force view my_view as
select * from dual;

exec dbms_utility.compile_schema(user, false);

create or replace force view my_view as
select * from dual
where 1 = my_utils.get_1();

select object_name from user_objects where status <> 'VALID';

【讨论】:

  • 这不适用于 11.2.0.3.0。 dummy-version 技巧适用于简单的 2 向依赖,但在这种情况下似乎不起作用。
  • @jonearles 我在 11.1.0.6 上对其进行了测试,它运行良好。如果您在 11.2.0.3 上测试它 - 重新编译后所有对象都无效吗?
  • 是的,它们都是无效的。它在 Express Edition 11.2.0.2 上也失败了,这里是 SQL Fiddle。也许这是 11.2 中的一个错误,但我在 Oracle 支持上找不到任何东西。
  • 这种方法也适用于 10.2.0.5,所以这个问题在 11gR2 中肯定是新问题。
猜你喜欢
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-12
  • 2021-10-02
相关资源
最近更新 更多