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

时间:2017-12-06 18:42:59

标签: sql oracle function plsql

我创建了一个包,它在同一页面内的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;
/

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

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

PLS-00231: function 'FF' may not be used in SQL

该功能在那里宣布。它不执行任何非查询DML。它在标头中没有任何PL / SQL特定的数据类型。

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

1 个答案:

答案 0 :(得分:4)

这是底线:

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

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

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

有趣的是,请注意,您不必在静态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;