本节将讲述如何利用 UNION 操作符将多条 SELECT 语句的结果组合成一个结果集

组合查询

多数 SQL 查询只包含从一个或多个表中返回数据的单条 SELECT 语句。但是,SQL 也允许执行多个查询(多条 SELECT 语句),并将结果作为一个查询结果返回。这些组合查询通常被称为 并(union)复合查询(compound query)

主要有两种情况需要使用组合查询:

  • 在一个查询中从不同的表返回数据结构
  • 对一个表执行多个查询,按一个查询返回数据
说明:组合查询和多个 WHERE 条件

多数情况下,组合相同表的两个查询所完成的工作与具有多个 WHERE 子句条件的一个查询所完成的工作相同。换句话说,任何具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询,在下面可以看到这一点

创建组合查询

使用 UNION

很简单,只需要在各条 SELECT 之间加上 UNION 就好了

举个例子,假如需要 Illinois、Indian 和 Michigan 等美国几个州的所有顾客的报表,还想包括不管位于那个州的所有的 Fun4All

这当然可以使用 WHERE 子句,例如下面这样

1
2
3
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI') OR cust_name = 'Fun4All';

而如果使用 UNION ,则会是这样

1
2
3
4
5
6
7
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

image-20220623221928698

在这个简单的例子中,使用 UNION 的确比使用 WHERE 更加复杂。但是对于较复杂的过滤条件,或从多个表(而不是一个表)中检索数据的情形,使用 UNION 可能会更简单

提示:UNION 的限制

使用 UNION 组合 SELECT 语句的数目,SQL 没有标准限制,但是 DBMS 可能会有限制

UNION 规则

可以看到,UNION 非常容易使用,但在进行组合时需要注意几条规则

  • UNION 必须由两条或两条以上的 SELECT 语句组成,语句之间使用 UNION 分隔
  • UNION 中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)
  • 列数据类型必须兼容:类型不必完全相同,但是必须是 DBMS 可以隐式转换的类型
提示:UNION 的列名

如果结合的两个查询使用不同的列名,那会返回什么名字呢?例如第一个语句是 SELECT prod_name,而第二个是 SELECT productname

答案是使用第一个名字,举得这个例子会返回 prod_name ,而不管第二个名字。这意味着你可以对第一个名字使用别名,而自定义返回的列名。同时如果排序的话也只能使用第一个名字

包含或取消重复的行

如果你单独执行上面被组合起来的两个查询语句,你会发现第一条会返回 3 行,第二条会返回 2 行,而且这两组结果中有一行是相同的

image-20220623222047270

但是将这两个组合在一起,就只会返回 4 行,而不是 5 行,可见 UNION 默认会自动去重

如果需要改变这一点,可以使用 UNION ALL ,这样会返回所有的匹配行

1
2
3
4
5
6
7
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

image-20220623222419864

前面说过, UNION 几乎总是完成与多个 WHERE 条件相同的工作。但是 UNION ALL 作为 UNION 的一种形式,它能完成 WHERE 不能完成的工作

对组合查询结果排序

SELECT 语句使用 ORDER BY 子句排序,在用 UNION 组合查询时,只能用一条 ORDER BY 子句,它必须在最后一条 SELET 语句之后。对于结果集,不能使用一种方式排序一部分,而又用另一种方式排序另一部分,因此不允许使用多条 ORDER BY 子句

下面的例子对前面 UNION 返回的结果进行排序

1
2
3
4
5
6
7
8
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'
ORDER BY cust_name, cust_contact;

image-20220623224041528

虽然 ORDER BY 子句看上去只是最后一条 SELECT 的一部分,但实际上它对整个结果集进行排序

说明:其他类型的 UNION

某些 DBMS 还支持另外两种 UNION

  • EXCEPT(有时称为 MINUS ),检索只在第一个表中存在而第二个表中不存在的行
  • INTERSECT ,检索两个表中都存在的行

实际上,这些 UNION 很少使用,因为相同的结果可以通过联结得到

提示:操作多个表

本节的例子都是使用 UNION 来组合查询一个表,但是 UNION 在需要组合多个表的数据时也很有用,即使是有不匹配的列名的表