如何将存储在表中的SQL语句用作另一个语句的一部分?

Sve*_*sli 5 sql oracle rules business-rules

在我们的Oracle数据库中,我们有一个名为RULES的表,其中包含一个名为SQLQUERY的字段.该字段是一个存储了SQL语句的varchar.PK是DM_PROJECT.

存储的典型语句可以是

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > 500000
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情:

select 
  * 
from 
  customers 
where
     accountnumber like 'A%'
  or salesregion = 999
  or accountnumber in
     (
       <run the query SQLQUERY from RULES where DM_PROJECT=:DM_PROJECT>
     )
Run Code Online (Sandbox Code Playgroud)

可以这样做吗?

(次要问题:如果存储的查询使用自己的变量,可以这样做,例如

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATEDSALES > :LIMIT 
Run Code Online (Sandbox Code Playgroud)

)

APC*_*APC 10

确实有趣的问题.这有两个方面.

首先是这是一个好主意.问题是,RULE中的文本对数据库是不可见的.它不会出现在依赖性检查中,因此影响分析变得很难.显然(或者可能不是很明显)规则的语法只能通过运行来验证.这可能会在添加规则时产生问题.所以它也可能是一个维护问题.而且,正如我们将要看到的,一旦你超越简单化的查询,就很难编程.

第二个方面是它是否可能.它是.我们需要使用动态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')
/
Run Code Online (Sandbox Code Playgroud)

此函数获取规则,执行它并返回数值数组.

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;
/
Run Code Online (Sandbox Code Playgroud)

让我们测试一下.

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>
Run Code Online (Sandbox Code Playgroud)

这是唯一正确的答案.

但现在我们来讨论你的问题:

"如果存储的查询使用自己的变量,是否可以完成"

是的,它可以,但事情开始变得更脆弱.新规则:

insert into rules 
values ('SO', 'ACC_SALES_VAR'
        , 'select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > :LMT ')
/
Run Code Online (Sandbox Code Playgroud)

我们修改函数来应用它:

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;
/
Run Code Online (Sandbox Code Playgroud)

手指交叉!

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>
Run Code Online (Sandbox Code Playgroud)

好的,所以它仍然有效.但你可以看到排列不友好.如果要将多个参数传递给RULE,则需要更多函数或更复杂的内部逻辑.如果要返回日期或字符串集,则需要更多函数.如果要传递不同data_types的P_VARIABLE参数,可能需要更多函数.你当然需要一些类型检查前置条件.

这回到了我的第一点:是的,它可以做到,但这是麻烦吗?