【问题标题】:Why do I get PLS-00302: component must be declared when it exists?为什么我会得到 PLS-00302:组件必须在存在时声明?
【发布时间】:2015-04-26 16:23:21
【问题描述】:

我使用的是 Oracle 10.2。

我正在编写一些脚本以将一些 ORACLE 对象从一个 SCHEMA (S1) 移动到另一个 (S2)。 我正在创建具有 DBA 角色的函数。 移动时,我的一个功能变得无效,但我不明白为什么。 它的代码是这样的:

MY_FUNC

CREATE OR REPLACE FUNCTION S2."MY_FUNC" RETURN VARCHAR2 IS
   something VARCHAR2;
   othervar VARCHAR2 (50):= 'TEST';   
BEGIN
   something := S2.MY_FUNC2();
    /*some code*/
    return othervar;
END;
/

如果我在没有架构的情况下使用 MY_FUNC2,它可以工作:
something := MY_FUNC2(); 而不是 something := S2.MY_FUNC2();

My_FUNC2

CREATE OR REPLACE FUNCTION S2."MY_FUNC2" RETURN VARCHAR2 IS
       something BOOLEAN;
       othervar VARCHAR2 (50) := 'TEST2';           
    BEGIN
       /*some code*/
        return othervar;
    END;
    /

MY_FUNC2 有这样的同义词:

 CREATE OR REPLACE PUBLIC SYNONYM "MY_FUNC2" FOR "S2"."MY_FUNC2"

MY_FUNC 编译出错:

PLS-00302:必须声明组件“MY_FUNC2”

我不明白为什么会出现此错误,当我的函数位于其他模式 (S1) 中时,它们具有完全相同的结构并且创建的同义词完全相同(但指向 S1)和 MY_FUNC编译好。

我最初并没有创建这个函数和同义词。是不是我在 S2 中遗漏了一些权限,所以MY_FUNC 可以正常工作?

【问题讨论】:

  • 你是从 s1 还是 s2 调用函数?
  • 如果您从 s1 进行调用,您需要将 s2.MY_FUNC2 的执行权限授予 s1。
  • 据我了解,这与调用无关,它甚至无法编译。所以只是为了确保,因为你的问题并不清楚。您是以 sys 还是 s2 身份登录的?您首先创建了 MY_FUNC2,然后创建了公共同义词,然后创建了 MY_FUNC?如果您是具有创建公共同义词特权的 SYS 或 S2 并按此顺序执行,则没有理由不编译(除了 my_func 声明了 varchar2; 没有精度)
  • @Aramillo 一切都在 S2 中,我使用 DBA 角色登录。 Alex 在下面描述了这个问题。
  • 另一种解决方案:stackoverflow.com/questions/2834596/…

标签: oracle plsql oracle10g


【解决方案1】:

如果您有一个与架构同名的对象,您可能会收到该错误。例如:

create sequence s2;

begin
  s2.a;
end;
/

ORA-06550: line 2, column 6:
PLS-00302: component 'A' must be declared
ORA-06550: line 2, column 3:
PL/SQL: Statement ignored

当您引用 S2.MY_FUNC2 时,对象名称正在被解析,因此它不会尝试将 S2 评估为模式名称。当您将其称为 MY_FUNC2 时,不会有任何混淆,因此可以正常工作。

文档explains name resolution。限定对象名称的第一部分(此处为 S2)在被评估为不同的架构之前被评估为当前架构上的对象。

它可能不是一个序列;其他对象可能会导致相同的错误。您可以通过查询数据字典来检查是否存在同名对象。

select owner, object_type, object_name
from all_objects
where object_name = 'S2';

【讨论】:

  • 谢谢亚历克斯!这似乎是有道理的,它们有一个与 Schema 同名的视图。有没有办法让 Oracle 将 S2 解释为模式而不是视图?
  • @Dzyann - 不符合那些搜索规则。为什么你有资格呢?如果您指的是同一架构中的某些内容,那么使用架构名称作为前缀并没有真正的好处?
  • 好吧,起初我只是不明白为什么这在一种模式中有效,而在另一种模式中无效。同样在理解了这个问题之后,我意识到这也会发生在其他模式中。从 S1 调用 MY_FUNC2 失败,因为 Oracle 首先找到 S2 视图的 SYNONYM,而不是 S2 模式。基本上,由于我不能强制 oracle 将 S2 解释为模式,我认为要走的路是更改 S2 视图的名称及其 PUBLIC SYNONYM。
  • 可能;有冲突的标识符充其量只会引起混淆。有些人喜欢使用匈牙利符号或变体,这往往会避免这种事情,但其他人则鄙视它,并且标识符长度的限制无论如何都会让它变得尴尬。 (虽然 S2 对于视图名称或模式名称似乎不是很有描述性,但并不总是在我们的控制之下......)
  • 再次感谢您提供了很多帮助。 S2不是真名,我只是用它来简化我的帖子,真名其实很好,我正在想一个不错的简短替代。
【解决方案2】:

我来这里是因为我遇到了同样的问题。
对我来说问题是程序是在包体中定义的,而不是在包头中定义的。
我正在使用一个丢失的 BEGIN END 语句执行我的函数。

【讨论】:

  • 祝福你 :) 我也遇到了同样的问题,忘记了包装规格
  • 我遇到了同样的情况,但在遗留代码中。该程序是本地程序,对外界不可见。解决方案是寻找一些可以调用它的父过程。这一次,父过程是在头中声明的
猜你喜欢
  • 2021-05-05
  • 2019-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-05
  • 1970-01-01
  • 2021-01-06
相关资源
最近更新 更多