Как использовать константу пакета в SQL-запросе SELECT?
Заголовок: Использование переменной пакета в простом SELECT-запросе в Oracle
Описание проблемы: Как я могу использовать переменную пакета в простом запросе SELECT в Oracle?
Я хотел бы написать что-то подобное:
SELECT * FROM MyTable WHERE TypeId = MyPackage.MY_TYPE;
Это возможно или данная конструкция работает только в PL/SQL (например, внутри блока BEGIN/END)?
4 ответ(ов)
Вы не можете.
Чтобы использовать публичную переменную пакета в SQL-запросе, вам нужно создать обертку (wrap) в виде функции, чтобы сделать значение доступным извне:
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.
Таким образом, вам необходимо использовать функцию, чтобы получить доступ к константе из пакета в SQL-запросе.
Существует более универсальный способ, который отлично подходит для меня. Вы можете создать функцию с входным параметром — именем константы (например, schema.package.constantname), которая будет возвращать значение этой константы. Используя оператор execute immediate
, вы можете выполнить блок PL/SQL с привязкой переменной res
(см. пример).
Функция будет выглядеть следующим образом:
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-запросе, например:
select GETCONSTANTVALUE('PKGGLOBALCONSTANTS.constantname') from dual;
Таким образом, вам нужна всего одна функция, и вы получаете возможность использовать существующие константы пакетов.
Обратите внимание: я пробовал это только в 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_DOUBLE
-----------------------
1.797693134862316E+308
SQL> select to_char(undefined_double,'9.99999999999999999EEEE') from dual;
TO_CHAR(UNDEFINED_DOUBLE,
-------------------------
1.79769313486231550E+308
Таким образом, вы можете легко возвращать значения с помощью функций и использовать их в своих запросах.
Нет, вы не можете так делать. Вам нужно создать функцию, которая возвращает значение, а затем использовать это в SQL-запросе:
SELECT * FROM MyTable WHERE TypeId = MyPackage.FUN_MY_TYPE
Получить строки с максимальным значением в одном столбце для каждого уникального значения другого столбца
Как выполнить сброс вывода из PL/SQL в Oracle?
Тип данных Oracle Timestamp
Как посчитать количество вхождений символа в значении varchar Oracle?
Как сравнить строки в SQL, игнорируя регистр?