如何使用存储在表中的SQL语句作为另一个语句的一部分?
问题描述:
在我们的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
)
答
确实有趣的问题。这有两个方面。
首先是它是否是一个好主意。问题是,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参数,你可能需要更多的功能。你当然需要一些类型检查前提条件。
回到我的第一个观点:是的,它可以完成,但这是麻烦吗?
有趣的问题! – Flukey 2010-08-12 10:03:58
内部平台效应再次出现! – 2010-08-12 16:57:46