我有2个SQL(Oracle 11g)查询:
select x1,x2,x3
from X
where x1 = a and x2 = b;
select x1,x2,x3
from X
where x1 = a and x2 = b and x3 = c;
他们选择表X中的相同列但条件不同。我使用UNION进行合并结果:
select x1,x2,x3,'Q1' as QueryCode
from X
where x1 = a and x2 = b
UNION
select x1,x2,x3,'Q2' as QueryCode
from X
where x1 = a and x2 = b and x3 = c;
但在这种情况下,我的表格数据太大,而且我不想选择它太多次。有人能给我一个关于构建查询返回相同结果的最佳方法的想法吗?
答案 0 :(得分:1)
如果对于X3='c'
,如果你真的需要2行,一行是Q1,另一行是Q1,那么联合查询是最好的。
我尝试使用X1=a and X2=b
创建CTE,然后再进行联合。成本略高于正常的联合查询。
继续union
。
此外,如果这些列未编入索引,请尝试将其编入索引。表现会有所改善。
答案 1 :(得分:1)
我们可以获取所有需要的行,在第一个和第二个过滤器之间添加OR
,然后在UNION
中将它们分开。使用提示/*+ materialize */
,我们确保只选择original_table
中的数据,并将结果存储在内存中的过滤结果sub_table
,以便当前查询执行。
是的,复制代码(x1 = a AND x2 = b)
和(x1 = a AND x2 = b AND x3 = c)
不是很美,但在这种太大的数据的情况下,我们做了另一个很好的权衡:一个小的重复精彩的表演。
WITH
sub_table AS (SELECT /*+ materialize */ x1, x2, x3
FROM original_table
WHERE (x1 = a AND x2 = b) -- first filter
OR (x1 = a AND x2 = b AND x3 = c) -- second filter
)
SELECT x1, x2, x3, 'Q1' AS querycode
FROM sub_table
WHERE x1 = a AND x2 = b -- first filter (repeated)
UNION
SELECT x1, x2, x3, 'Q2' AS querycode
FROM sub_table
WHERE x1 = a AND x2 = b AND x3 = c; -- second filter (repeated)
如果我们不关心行顺序,那么另一种方法是UNION
:
SELECT x1, x2, x3,
CASE
WHEN x1 = a AND x2 = b THEN 'Q1'
WHEN x1 = a AND x2 = b AND x3 = c THEN 'Q2'
END AS marker
FROM original_table
WHERE CASE
WHEN x1 = a AND x2 = b THEN 'Q1'
WHEN x1 = a AND x2 = b AND x3 = c THEN 'Q2'
END IS NOT NULL;
仍然存在代码重复的不完美,但这是一个代价 用于查询具有大数据的表。换句话说,对于一个小桌子 我们可以使用带有子查询的简洁代码,这更加占用内存:
SELECT *
FROM (SELECT x1, x2, x3,
CASE
WHEN x1 = a AND x2 = b THEN 'Q1'
WHEN x1 = a AND x2 = b AND x3 = c THEN 'Q2'
END AS marker
FROM original_table) t
WHERE t.marker IS NOT NULL;
最后,在Oracle 12c中,我们可以将这个重复的CASE
封装到一个函数中:
WITH
FUNCTION get_marker(x1 CHAR, x2 CHAR, x3 CHAR) RETURN CHAR DETERMINISTIC
IS
BEGIN
RETURN CASE
WHEN x1 = a AND x2 = b THEN 'Q1'
WHEN x1 = a AND x2 = b AND x3 = c THEN 'Q2'
END;
END
SELECT x1, x2, x3,
get_marker(x1, x2, x3) AS marker
FROM original_table
WHERE get_marker(x1, x2, x3) IS NOT NULL;