【问题标题】:How to use a package constant in SQL SELECT statement?如何在 SQL SELECT 语句中使用包常量?
【发布时间】:2011-07-07 22:07:21
【问题描述】:

如何在 Oracle 的简单 SELECT 查询语句中使用包变量?

类似

SELECT * FROM MyTable WHERE TypeId = MyPackage.MY_TYPE

是否有可能或仅在使用 PL/SQL 时(在 BEGIN/END 中使用 SELECT)?

【问题讨论】:

    标签: sql oracle packages


    【解决方案1】:

    你不能。

    对于要在 SQL 语句中使用的公共包变量,您必须编写一个包装函数以将值公开给外界:

    SQL> create package my_constants_pkg
      2  as
      3    max_number constant number(2) := 42;
      4  end my_constants_pkg;
      5  /
    
    Package created.
    
    SQL> with t as
      2  ( select 10 x from dual union all
      3    select 50 from dual
      4  )
      5  select x
      6    from t
      7   where x < my_constants_pkg.max_number
      8  /
     where x < my_constants_pkg.max_number
               *
    ERROR at line 7:
    ORA-06553: PLS-221: 'MAX_NUMBER' is not a procedure or is undefined
    

    创建一个包装函数:

    SQL> create or replace package my_constants_pkg
      2  as
      3    function max_number return number;
      4  end my_constants_pkg;
      5  /
    
    Package created.
    
    SQL> create package body my_constants_pkg
      2  as
      3    cn_max_number constant number(2) := 42
      4    ;
      5    function max_number return number
      6    is
      7    begin
      8      return cn_max_number;
      9    end max_number
     10    ;
     11  end my_constants_pkg;
     12  /
    
    Package body created.
    

    现在它可以工作了:

    SQL> with t as
      2  ( select 10 x from dual union all
      3    select 50 from dual
      4  )
      5  select x
      6    from t
      7   where x < my_constants_pkg.max_number()
      8  /
    
             X
    ----------
            10
    
    1 row selected.
    

    【讨论】:

    • 你应该标记游览功能deterministic,否则Oracle会在每次需要时不必要地调用它max_number
    【解决方案2】:

    有一种更通用的方法对我来说很好用。您使用输入常量名称(即 schema.package.constantname)创建一个函数,它会返回常量值。您可以通过绑定 res 变量来立即执行 PL/SQL 块(参见示例)。

    函数如下所示:

    CREATE OR REPLACE FUNCTION GETCONSTANTVALUE (i_constant IN VARCHAR2)  RETURN NUMBER deterministic AS
    
       res number; 
    BEGIN
    
       execute immediate 'begin :res := '||i_constant||'; end;' using out res;     
       RETURN res;
    
    END;
    /
    

    然后您可以在任何 SQL 中使用任何包的常量,即 like

    select GETCONSTANTVALUE('PKGGLOBALCONSTANTS.constantname') from dual;
    

    像这样你只需要 1 个函数,你就可以利用现有的 packages.constants。

    【讨论】:

    • 感谢deterministic 子句,这是一个不错的解决方案。
    • 好主意,唯一的缺点是错误(例如由于拼写错误)直到运行时才会出现 - 即使您引用不存在的常量,您的查询也将无错误地编译。
    • 谢谢,我认为这个答案比公认的要好。
    • 这可能会将数据库暴露给 SQL 注入。
    【解决方案3】:

    注意:我只在 Oracle 11g 中尝试过。

    我有类似的需求,发现简单地声明一个函数(没有包)来返回所需的值更容易。要将这些放在 ddl 中进行导入,请记住用 / 字符分隔每个函数声明。例如:

    CREATE OR REPLACE FUNCTION UNDEFINED_INT RETURN NUMBER AS BEGIN RETURN 2147483646; END;
    /
    CREATE OR REPLACE FUNCTION UNDEFINED_SHORT RETURN NUMBER AS BEGIN RETURN 32766; END;
    /
    CREATE OR REPLACE FUNCTION UNDEFINED_LONG RETURN NUMBER  AS BEGIN RETURN 223372036854775806; END;
    /
    CREATE OR REPLACE FUNCTION UNDEFINED_FLOAT RETURN FLOAT  AS BEGIN RETURN .4028233E38; END;
    /
    CREATE OR REPLACE FUNCTION UNDEFINED_DOUBLE RETURN BINARY_DOUBLE  AS BEGIN RETURN to_binary_double('1.7976931348623155E308'); END;
    /
    CREATE OR REPLACE FUNCTION UNDEFINED_STRING RETURN VARCHAR AS BEGIN RETURN '?'; END;
    /
    

    这使您可以像引用常量值一样引用函数(例如,您甚至不需要括号)。

    例如(注意显示精度的 to_char 方法已被保留): SQL> select undefined_int from dual;

    UNDEFINED_INT
    -------------
       2147483646
    

    SQL> select undefined_string from dual;

    UNDEFINED_STRING
    --------------------------------------------------------------------------------
    ?
    

    SQL> select undefined_double from dual;

    UNDEFINED_DOUBLE
    ----------------
          1.798E+308
    

    SQL> select to_char(undefined_double,'9.999999999999999EEEE') from dual;

    TO_CHAR(UNDEFINED_DOUBL
    -----------------------
     1.797693134862316E+308
    

    SQL> select to_char(undefined_double,'9.99999999999999999EEEE') from dual;

    TO_CHAR(UNDEFINED_DOUBLE,
    -------------------------
     1.79769313486231550E+308
    

    【讨论】:

      【解决方案4】:

      不,你不能这样做。您需要提供一个返回值的函数,然后在 SQL 中使用它:

      SELECT * FROM MyTable WHERE TypeId = MyPackage.FUN_MY_TYPE
      

      【讨论】:

        猜你喜欢
        • 2013-09-28
        • 2017-03-29
        • 1970-01-01
        • 2021-01-28
        • 2012-06-16
        • 2023-03-06
        • 1970-01-01
        • 1970-01-01
        • 2018-05-12
        相关资源
        最近更新 更多