【MySQL必知必会】:组合查询(UNION、UNION ALL)

172 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 28 天,点击查看活动详情

本节主要记录了如何使用 UNION 操作符将多条 SELECT 语句组合成一个结果集。

组合查询

大多数 SQL 查询都是只包含了单条 SELECT 语句。现在,我们还可以使用 UNION 操作符来组合多条 SQL 查询,让 MySQL 执行多条 SELECT 语句,并将结果作为单个查询结果集返回。

这种多条 SELECT 语句组合查询的情况通常被称为并(union)查询 或者 复合(compound)查询。

组合查询和多个 WHERE 条件

  • 多数情况下,组合相同表的两个查询完成的工作与具有多个 WHERE 子句条件的单条查询完成的工作相同。
  • 换句话说,任何具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询给出。

创建组合查询

使用 UNION

先来看两个例子:

  • 检索价格小于等于 100 的所有产品:
select
    vend_id, prod_id, prod_price
from
    products
where
    prod_price <= 100;
  • 检索 供应商ID 为 1001 和 1009 生产的所有物品:
select
    vend_id, prod_id, prod_price
from
    products
where
    vend_id in (1001, 1009);
  • 现在,我们使用 UNION 操作符来组合这两条 SQL 查询:
select
    vend_id, prod_id, prod_price
from
    products
where
    prod_price <= 100
union
select
    vend_id, prod_id, prod_price
from
    products
where
    vend_id in (1001, 1009);

记录:

  • 可以看到,UNION 操作符将两条 SELECT 语句组合在一起,其中,两条语句用UNION 关键字分隔。
  • 也就是说,UNION 操作符指示 MySQL 执行两条 SELECT 语句,并将输出组合成单个查询结果集。

另一方面,我们也意识到,这个组合查询可以使用多条 where 子句进行代替,如下所示:

select
    vend_id, prod_id, prod_price
from
    products
where
    prod_price <= 100 or vend_id in (1001, 1009);

事实上,无论是组合查询还是使用多个 WHERE 条件,都是可行的。这两种技术在不同的查询中性能也不同。

对于复杂的过滤条件或者从多个表中检索数据的情况时,使用组合查询可能会使处理更简单。

注意事项

在使用组合查询时(UNION),注意事项如下:

  • union 操作符必须由两条或两条以上的 select 语句组成,语句之间用关键字union 进行分隔(组合 3 条 select 语句将要使用 2 个union 操作符)
  • union 组合的每个查询语句必须包含相同的列、表达式或聚集函数(次序不要求)
  • 列数据必须兼容,数据类型不必完全相同,但是必须是 MySQL 中可以隐含地转换的类型。
  • 在使用 union 进行组合查询时,只能使用一条 order by 子句(不允许使用多条 order by 子句)

包含或取消重复的行

union 操作符在查询时有一个默认行为,即从查询结果集中自动去除了重复的行。

比如之前我们记录的例子:

select
    vend_id, prod_id, prod_price
from
    products
where
    prod_price <= 100
union
select
    vend_id, prod_id, prod_price
from
    products
where
    vend_id in (1001, 1009);

在上述例子中:

  • 第一条 select 语句返回了 4 行数据,第二条 select 语句返回了 5 行数据,但是使用 union 操作符组合两条 select 语句后返回了 8 行数据(而不是 9 行)。
  • 这是因为在第二条查询语句中,供应商 1009 生产的一种产品,价格也低于 100。而 union 操作符从查询结果集中自动去除了重复的行(这种默认行为和使用多条 where 子句的效果一样)

如果我们想要改变这种 union 操作符的默认行为,使得所有的匹配行都可以返回,此时可以使用 union all

比如:

select
    vend_id, prod_id, prod_price
from
    products
where
    prod_price <= 100
union all
select
    vend_id, prod_id, prod_price
from
    products
where
    vend_id in (1001, 1009);

记录:

  • union allunion 的一种形式,它完成了 where 子句完成不了的工作
  • 如果确实需要每个条件的匹配行全部出现(包括重复行),则必须使用 union all 而不是 多条 where 子句。

小结

在哪些情况下可以尝试使用组合查询呢?

如下所示:

  • 在单个查询中从不同的表返回类似结构的数据
  • 对单个表执行多个查询,按单个查询返回数据