如何将查询存储到变量中

时间:2016-09-06 03:34:26

标签: oracle performance plsql query-optimization

假设我有这个复杂的查询代码段

select id, name, count(*)
from items
join ...
where <where_1st>
group by ...
having <having_1st>

来自items

的表格定义
items
-----
id ID
name varchar2
quantity number
price number
...

如何将该查询存储到变量中,以便我可以使用该查询中的字段,同时以union all格式加入该查询。这样的事情。

最终查询:

select id, name, count(*)
from items
join ...
where <where_2nd> and id not in (<first_query>.id/s)
group by ...
having <having_2nd>

union all

<first query>;

可以这种格式完成吗?

DECLARE
  <variable_for_1st_query>
BEGIN
  <final_query>
END;

注意:查询范围广泛且复杂。采用这种方法将计算时间减少一半。

3 个答案:

答案 0 :(得分:2)

您要做的是重复使用第一个查询的结果集作为第二个查询的过滤器,同时还在最终输出中包含其行。有两种方法可以做到这一点,但最简单的 - 不需要PL / SQL - 是子查询因为AKA with子句。 with语句执行一次,结果集用于引用子查询的任何位置。

所以,在你的例子中:

with q1 as (
    select id, name, count(*)
    from items
    join ...
    where <where_1st>
    group by ...
    having <having_1st> 
)
select id, name, count(*)
from items
join ...
where <where_2nd> 
and id not in (select q1.id from q1)
group by ...
having <having_2nd>
union all
select * from q1;

因为这种方法是纯SQL,所以很容易读取结果集。 PL / SQL方法需要更多的基础设施。

答案 1 :(得分:1)

假设您想要使用第一次查询的结果两次:

  • 供您自己选择
  • 在第二次选择中排除相同的ID

如果您的第一个和第二个选择为count(*)提供了相同的结果,那么您只需使用union代替union all并删除第二个选择语句中的and id not in (<first_query>.id/s)子句。

e.g。

-- test data for "items"
with items(id, name, val) as
 (select 1, '101', 101 from dual
  union all
  select 1, '101', 501 from dual
  union all
  select 2, '202', 202 from dual
  union all
  select 2, '202', 302 from dual
  union all
  select 3, '301', 103 from dual
  union all
  select 5, '105', 105 from dual)

select i.id, i.name, count(*)
  from items i
 where i.id < 5 -- different select ranges
 group by i.id, i.name
having avg (val) between 200 and 505 -- different group criterias

union 

select i.id, i.name, count(*)
  from items i
 where i.id > 1 --
 group by i.id, i.name
having sum (val) <= 505; --

--> result:

1   101 2
2   202 2  -- result is in both selects
3   301 1
5   105 1

如果您的第一个和第二个选择为count(*)提供不同的结果,那么您可以通过

来实现
-- select all
with data as (
select 1 as select_id, id, name, count(*) as total
from items
join ...
where <where_first> 
group by ...
having <having_first>
union all
select 2 as select_id, id, name, count(*) as total
from items
join ...
where <where_2nd> 
group by ...
having <having_2nd>)
-- filter results by select_id
select d.id, d.name, d.total from data d
where d.select_id = (select min(dd.select_id) from data dd where dd.id=d.id)

答案 2 :(得分:0)

DECLARE 

v_query_1       VARCHAR2(100);
v_query_2       VARCHAR2(200);
v_query_3       VARCHAR2(300);
v_query_main    VARCHAR2(500);

BEGIN

v_query_1    := 'First query';
v_query_2    := 'Second query';
v_query_3    := 'Third query';
v_query_main := v_query_1||'UNION ALL'||v_query_2||'UNION ALL'||v_query_3;

EXECUTE IMMEDIATE v_query_main;

END;
/