为什么我不能在 SQL 语句中调用我的函数?

Ste*_*ein 4 sql oracle plsql function

我创建了一个包,该包在同一页面内的 SELECT 语句中执行我的函数:

CREATE OR REPLACE PACKAGE p
   AUTHID DEFINER
IS
   FUNCTION f
      RETURN NUMBER;
END;
/

CREATE OR REPLACE PACKAGE BODY p
IS
   FUNCTION ff RETURN NUMBER
   IS
   BEGIN
      RETURN 73;
   END;

   FUNCTION f RETURN NUMBER
   IS
      l_number   NUMBER;
   BEGIN
      SELECT 42 INTO l_number
        FROM DUAL
       WHERE ff () = 73;

      RETURN l_number;
   END;
END;
/

BEGIN
   DBMS_OUTPUT.put_line (p.f);
END;
/
Run Code Online (Sandbox Code Playgroud)

但是当我尝试执行该函数时,出现 PLS-00231 编译错误:

BEGIN
   dbms_output.put_line (P.F);
END;
/

PLS-00231: function 'FF' may not be used in SQL
Run Code Online (Sandbox Code Playgroud)

该函数就在那里声明。它不执行任何非查询 DML。它的标头中没有任何特定于 PL/SQL 的数据类型。

为什么 SQL 不能使用/看到它?

Ste*_*ein 8

这是底线:

如果要从 SQL 语句中调用函数,则它必须在模式级别 (CREATE FUNCTION) 中声明或在包的规范中定义。即使您的 SQL 语句位于与调用的函数相同的包中的子程序中,也是如此。

因此,如果我按如下方式更改包规范,公开以前的私有函数,一切都很好:

CREATE OR REPLACE PACKAGE p AUTHID DEFINER
IS
   FUNCTION f RETURN NUMBER;
   FUNCTION ff RETURN NUMBER;
END;
/
Run Code Online (Sandbox Code Playgroud)

请注意,有趣的是,您不必在静态 SQL 语句中用包名限定函数名。PL/SQL 编译器在将语句传递给 SQL 引擎之前对其进行排序。

但是,如果动态执行 SQL,则需要包名称,如下所示:

FUNCTION f RETURN NUMBER
IS
   l_number NUMBER;
BEGIN
   EXECUTE IMMEDIATE 
      'SELECT 42 FROM DUAL WHERE p.ff () = 73'
      INTO l_number;

   RETURN l_number;
END;
Run Code Online (Sandbox Code Playgroud)

  • 真的是你吗?不敢相信。 (2认同)