Действительно интересный вопрос. Здесь есть два аспекта.
Во-первых, хорошая ли это идея. Проблема в том, что текст в правиле невидим для базы данных. Он не будет отображаться при проверке зависимостей, поэтому анализ влияния становится сложным. Очевидно (или, может быть, не очевидно) синтаксис правила может быть проверен только путем его запуска. Это может создать проблемы с добавлением правил. Так что это также может быть проблемой обслуживания. И, как мы увидим, как только вы выйдете за рамки упрощенных запросов, будет сложно программировать.
Второй аспект - возможно ли это? Это. Нам нужно использовать динамический SQL; объединение динамического SQL со статическим SQL выполнимо, но довольно сложно.
create table rules (project_name varchar2(30)
, rule_name varchar2(30)
, rule_text varchar2(4000) )
/
insert into rules
values ('SO', 'ACC_SALES'
, 'select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > 500000 ')
/
create table customers (accountnumber number(7,0)
, name varchar2(20)
, accumulated_sales number
, sales_region varchar2(3))
/
insert into customers values (111, 'ACME Industries', 450000, 'AA')
/
insert into customers values (222, 'Tyrell Corporation', 550000, 'BB')
/
insert into customers values (333, 'Lorax Textiles Co', 500000, 'BB')
/
Эта функция получает правило, выполняет его и возвращает числовой массив.
create or replace type rule_numbers as table of number
/
create or replace function exec_numeric_rule
( p_pname in rules.project_name%type
, p_rname in rules.rule_name%type )
return rule_numbers
is
return_value rule_numbers;
stmt rules.rule_text%type;
begin
select rule_text into stmt
from rules
where project_name = p_pname
and rule_name = p_rname;
execute immediate stmt
bulk collect into return_value;
return return_value;
end exec_numeric_rule;
/
Давайте проверим это.
SQL> select * from customers
2 where accountnumber in
3 ( select * from table (exec_numeric_rule('SO', 'ACC_SALES')))
4 /
ACCOUNTNUMBER NAME ACCUMULATED_SALES SAL
------------- -------------------- ----------------- ---
222 Tyrell Corporation 550000 BB
1 row selected.
SQL>
Какой единственный и правильный ответ.
Но теперь мы подходим к вашему дополнительному вопросу:
"Можно ли это сделать, если сохраненный запрос
использует свои собственные переменные "
Да, может, но все становится немного более хрупким. Новое правило:
insert into rules
values ('SO', 'ACC_SALES_VAR'
, 'select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > :LMT ')
/
Мы изменим функцию, чтобы применить ее:
create or replace function exec_numeric_rule
( p_pname in rules.project_name%type
, p_rname in rules.rule_name%type
, p_variable in number := null)
return rule_numbers
is
return_value rule_numbers;
stmt rules.rule_text%type;
begin
select rule_text into stmt
from rules
where project_name = p_pname
and rule_name = p_rname;
if p_variable is null then
execute immediate stmt
bulk collect into return_value;
else
execute immediate stmt
bulk collect into return_value
using p_variable;
end if;
return return_value;
end exec_numeric_rule;
/
Пальцы скрещены!
SQL> select * from customers
2 where accountnumber in
3 ( select * from table (exec_numeric_rule('SO', 'ACC_SALES_VAR', 480000)))
4 /
ACCOUNTNUMBER NAME ACCUMULATED_SALES SAL
------------- -------------------- ----------------- ---
222 Tyrell Corporation 550000 BB
333 Lorax Textiles Co 500000 BB
2 rows selected.
SQL>
Хорошо, все еще работает. Но вы можете видеть, что перестановки не дружелюбны. Если вы хотите передать более одного аргумента в правило, то вам нужно больше функций или более крутой внутренней логики. Если вы хотите вернуть наборы дат или строк, вам нужно больше функций. Если вы хотите передать параметры P_VARIABLE различных типов данных, вам может потребоваться больше функций. Вам, безусловно, нужны предварительные условия проверки типов.
Что возвращает меня к первому пункту: да, это можно сделать, но стоит ли это хлопот?