如何在 SQL SELECT 语句中使用包常量?

Posted

技术标签:

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

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

类似

SELECT * FROM MyTable WHERE TypeId = MyPackage.MY_TYPE

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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于如何在 SQL SELECT 语句中使用包常量?的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL Server 中使用常量 1 或 0 隐含位

请问如何使用SQL语句查询同一张表中互为相反数的两条记录!如A1=500,A2=-500,如何写SQL语句

select语句如何查找某个时间段的数据

如何在shell 中将sql语句执行结果写入日志中

ogr执行sql语句,sql中有中文时包语法错误

如何从 sql 语句中返回常量?