【问题标题】:How can I use an SQL statement stored in a table as part of another statement?如何将存储在表中的 SQL 语句用作另一个语句的一部分?
【发布时间】:2011-03-28 20:04:00
【问题描述】:

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

存储的典型语句可能是

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 

)

【问题讨论】:

  • 内平台效应再次上演!

标签: sql oracle rules business-rules


【解决方案1】:

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

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

第二个方面是是否可能。它是。我们需要使用动态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>

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

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

【讨论】:

  • 很棒的答案。像你这样的人使 stackoverflow 变得很棒。干得好,陛下!
  • 我只需要同意 Jamie 的观点,这真的很有趣,也是一个很好的答案!肯定 +1。
  • +1:很好的回答。对于这种过程,管道函数可能比嵌套表执行得更好。
  • @Allan - 我怀疑流水线函数除了减慢速度之外还能做任何事情。结果是相同的,嵌套集合必须使用 TABLE() 函数进行转换。那么,为什么还要费心循环遍历变量管道的各个行呢?
  • @APC - 我也这么认为。事实上,我坚信我在 AskTom 上的 suggested using a nested table over a pipelined function(诚然是一个更简单的案例)并被告知我错了......老实说,我从来没有找到足够的解释来解释流水线函数背后的工作原理场景,但有限的测试表明它们往往比嵌套表解决方案更快。
【解决方案2】:

您可以使用动态 SQL(立即执行)..请参阅Execute Immediate 了解更多详情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 2014-02-11
    • 2012-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多