我们可以获取所有需要的行,在第一个和第二个过滤器之间添加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;