2010-08-12 57 views
4

在我们的Oracle数据库中,我们有一个名为RULES的表,其中有一个名为SQLQUERY的字段。该字段是一个存储了SQL语句的varchar。 PK是DM_PROJECT。如何使用存储在表中的SQL语句作为另一个语句的一部分?

存储可能是

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATED_SALES > 500000 

我想要做这样的事的典型声明:

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

可以这样做?

(次要问题:如果存储的查询使用它自己的变量能不能做到,像

select ACCOUNTNUMBER from CUSTOMERS where ACCUMULATEDSALES > :LIMIT 

+0

有趣的问题! – Flukey 2010-08-12 10:03:58

+1

内部平台效应再次出现! – 2010-08-12 16:57:46

回答

8

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

首先是它是否是一个好主意。问题是,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') 
/

该函数得到一个规则,执行它并返回一个数值数组。

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> 

这是唯一正确的答案。

但是,现在我们来到你suplementary问题:

是的,它可以“可不可以这样,如果存储的查询 使用其自己的变量做了”,但事情开始变得有点脆。新规则:

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> 

好的,所以它仍然有效。但是你可以看到排列并不友善。如果你想向RULE传递多个参数,那么你需要更多的函数或更复杂的内部逻辑。如果你想返回一组日期或字符串,你需要更多的功能。如果你想传递不同data_types的P_VARIABLE参数,你可能需要更多的功能。你当然需要一些类型检查前提条件。

回到我的第一个观点:是的,它可以完成,但这是麻烦吗?

+0

梦幻般的答案。像你这样的人是什么让stackoverflow真棒。干得好,陛下! – Flukey 2010-08-12 11:14:43

+0

我只需要在这里同意Jamie,这真的很有趣,很好的答案!肯定+1。 – wasatz 2010-08-12 11:20:14

+0

+1:非常好的答案。对于这种过程,管道函数可能比嵌套表执行得更好。 – Allan 2010-08-12 13:21:28

0

您可以使用动态SQL(立即执行)..please参考Execute Immediate更多细节。

相关问题