是否总是有可能避免在SQL中使用UNION?

时间:2018-12-18 18:32:57

标签: sql oracle

假设我有一个只有一列的超简单表(称为useful_table),如下所示:

+----------+
| a_number |
+----------+
|     2    |
|     4    |
|     8    |
+----------+

假设我有一个带有UNION的查询:

  SELECT
    a_number
  FROM
    useful_table
  WHERE
    a_number = 2
UNION
  SELECT
    a_number + 1
  FROM
    useful_table
  WHERE
    a_number = 2
;

我希望结果是:

+----------+
| a_number |
+----------+
|     2    |
|     3    |
+----------+

示例查询在Oracle中运行,但应适用于其他方言。

此处的设置代码:

create table useful_table(a_number NUMBER);
insert into useful_table values (2);
insert into useful_table values (4);
insert into useful_table values (8);

是否可以转换此查询?

是否总是有可能将UNION转换为替代项?

假设:

  • 我正在使用(Oracle)SQL的子集,这意味着:
    • 我不能使用临时表。
    • 我不能使用UNIONUNION ALL
  • UNION的两侧都访问同一表中的数据,但是可能以不同的方式更改原始数据。

3 个答案:

答案 0 :(得分:2)

始终可以将UNION重写为FULL OUTER JOIN

所以

  SELECT
    <expression1>
  FROM
    useful_table
  WHERE
    <predicate1>
UNION
  SELECT
   <expression2>
  FROM
    useful_table
  WHERE
    <predicate2>
;

将成为

SELECT DISTINCT COALESCE(u1.<expression1> , u2.<expression2> )
FROM            useful_table u1
FULL OUTER JOIN useful_table u2
ON              1 = 0
WHERE           u1.<predicate1>
                OR u2.<predicate2>

或者在您的特定示例中

SELECT DISTINCT COALESCE(u1.a_number, u2.a_number + 1)
FROM   useful_table u1
       FULL OUTER JOIN useful_table u2
                    ON 1 = 0
WHERE  u1.a_number = 2
        OR u2.a_number = 2 

答案 1 :(得分:1)

一种解决方案是使用CROSS JOIN cte的CONNECT BY复制输出行。

但是,一般来说,这是在以下假设下进行的:

  • 只涉及一张桌子
  • 只有一个WHERE子句
  • 对重复记录执行的操作非常简单,可以根据CONNECT BY cte返回的递增整数来实现(仍然有相当大的操作余地)

以下查询确实符合您的确切用例:

with data as (select level -1 l from dual connect by level <= 2)
select a_number + l
from useful_table, data
where a_number = 2

答案 2 :(得分:-3)

我将在没有其他方法的情况下使用Union。我一直发现,来自一个查询的联接和案例构造总是比联合表现更好。

但是,正如有人评论的那样,有时候行可以匹配两个案例标准,而案例逻辑无法实现。

查询是针对目标的,但我认为可以说不能总是取代Union。

在您的特定用例中,可以。