如何将查询存储到变量中

Posted

技术标签:

【中文标题】如何将查询存储到变量中【英文标题】:How to store a query into a variable 【发布时间】:2016-09-06 03:34:25 【问题描述】:

假设我有这个复杂的查询 sn-p

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;

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

【问题讨论】:

不太确定您要实现什么...您真的需要变量,还是只想降低第二个查询的复杂性?如果您不坚持使用变量,您可以使用view,或使用with data as (&lt;first query&gt;) ... Storing query into a variable的可能重复 供以后参考不要重复发布相同的问题。这令人困惑,只会浪费人们的时间。相反,如果您没有得到正确答案,您应该编辑原始问题以改进它。 要删除另一个。我很抱歉。 【参考方案1】:

您想要做的是重新使用第一个查询的结果集作为第二个查询的过滤器,同时还将其行包含在最终输出中。有几种方法可以做到这一点,但最简单的 - 不需要 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 方法需要更多的基础架构。

【讨论】:

【参考方案2】:

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

供您选择 在您的第二个选择中排除相同的 ID

如果您的第一个和第二个选择为count(*) 提供相同的结果,那么您可以简单地使用union 而不是union all,并在您的第二个选择语句中删除and id not in (&lt;first_query&gt;.id/s) 子句。

例如

-- 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)

【讨论】:

选项 1 不能保证返回所需的结果:在不知道 WHERE 子句的数据和详细信息的情况下,我们没有理由假设第二个子查询会返回与第一个子查询。 @APC 这正是我写的。 同意..弗兰克首先给出了相同的答案,奇怪的是他得到了 0 票......所以我 +1。 好的,请允许我重新表述我的观点:如果两个查询都为第一组中的每个 ID 返回相同的计数,那么进行两个查询就没有意义了。 @Raj_Te - 实际上我的解决方案在语义上与弗兰克的第二个解决方案不同,尽管我同意它们会产生相同的结果。我发布了我的解决方案,因为我认为它更能表达意图并且更接近 OP 的代码,但显然这是一个品味问题。之后,它归结为性能(毕竟它是 OP 的驱动程序)。那么,限制第二个查询还是只选择所有内容然后过滤是否更有效?这取决于执行计划和只有 OP 知道的所有其他内容。【参考方案3】:
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;
/

【讨论】:

以上是关于如何将查询存储到变量中的主要内容,如果未能解决你的问题,请参考以下文章

如何将子查询的值存储到 Hana Studio 中的变量中?

如何将从“选择”查询中获得的值存储到 ASP.net 中的会话变量中

如何将跨表查询的结果存储到表变量中

如何将数据库查询结果中的值存储到机器人框架中的变量中[重复]

如何将 MySql 查询的结果保存到 VB 变量中? [复制]

如何将 knex 查询存储在变量中?