我们前边说的都是单条查询语句,其实多条查询语句的查询结果也可以被合并起来,这种将多个查询的查询结果合并起来的查询方式称为合并查询
,或者组合查询
。
查询列表相同的情况
比如说下边这两条查询语句:
mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
+------+------+
1 row in set (0.00 sec)
mysql> SELECT m1, n1 FROM t1 WHERE m1 > 2;
+------+------+
| m1 | n1 |
+------+------+
| 3 | c |
+------+------+
1 row in set (0.00 sec)
mysql>
复制代码
这两个查询语句可以使用UNION
来合并起来:
mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m1, n1 FROM t1 WHERE m1 > 2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 3 | c |
+------+------+
2 rows in set (0.01 sec)
mysql>
复制代码
多个查询语句也直接用UNION
来合并起来:
mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m1, n1 FROM t1 WHERE m1 > 2 UNION SELECT m1, n1 FROM t1 WHERE m1 = 2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 3 | c |
| 2 | b |
+------+------+
3 rows in set (0.00 sec)
mysql>
复制代码
当然,这种将对于查询列表相同的多个查询合并起来的情况可以通过修改WHERE
子句来达到目的,比如上边的查询可以替换为:
SELECT m1, n1 FROM t1 WHERE m1 < 2 OR m1 > 2 OR m1 = 2;
复制代码
具体使用哪种查询方式还需要分析这两种查询的性能消耗,我们后边在优化查询时会详细唠叨的。
查询列表不同的情况
对于查询列表不同的情况就只能用UNION
来合并多个查询了,比方说下边这两个查询:
mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
+------+------+
1 row in set (0.00 sec)
mysql> SELECT m2, n2 FROM t2 WHERE m2 > 2;
+------+------+
| m2 | n2 |
+------+------+
| 3 | c |
| 4 | d |
+------+------+
2 rows in set (0.00 sec)
mysql>
复制代码
第一个查询是从t1
表中查询m1, n1
这两个列的数据,第二个查询是从t2
表中查询m2, n2
这两个列的数据。虽然m1、n1
和m2、n2
是两个不同的查询列表,但是这两个列组合中m1
和m2
都是整数类型的,n1
和n2
都是字符串类型的,所以也可以把它们的查询结果拼接到一起:
mysql> SELECT m1, n1 FROM t1 WHERE m1 < 2 UNION SELECT m2, n2 FROM t2 WHERE m2 > 2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 3 | c |
| 4 | d |
+------+------+
3 rows in set (0.01 sec)
mysql>
复制代码
不过需要注意,查询的结果集中显示的列名将以第一个查询中的列名为准。虽然几个查询的数据都可以被放入同一个结果集,但是结果集总是要有一个列名的吧,所以就规定采用第一个查询中的列名,上边的例子就采用了第一个查询中的m1, n1
作为结果集的列名。
包含或取消重复的行
我们看下边这两个查询:
mysql> SELECT m1, n1 FROM t1;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 2 | b |
| 3 | c |
+------+------+
3 rows in set (0.00 sec)
mysql> SELECT m2, n2 FROM t2;
+------+------+
| m2 | n2 |
+------+------+
| 2 | b |
| 3 | c |
| 4 | d |
+------+------+
3 rows in set (0.00 sec)
mysql>
复制代码
很显然,t1
表里有3条记录,t2
表里有3条记录,我们把它们合并起来看一下:
mysql> SELECT m1, n1 FROM t1 UNION SELECT m2, n2 FROM t2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 4 | d |
+------+------+
4 rows in set (0.00 sec)
mysql>
复制代码
为什么合并后的结果只剩下了4条记录呢?因为使用UNION
来合并多个查询的记录会默认过滤掉重复的记录。由于t1
表和t2
表都有(2, b)、(3, c)
这两条记录,所以合并后的结果集就把他俩去重了。如果我们想要保留重复记录,可以使用UNION ALL
来连接多个查询:
mysql> SELECT m1, n1 FROM t1 UNION ALL SELECT m2, n2 FROM t2;
+------+------+
| m1 | n1 |
+------+------+
| 1 | a |
| 2 | b |
| 3 | c |
| 2 | b |
| 3 | c |
| 4 | d |
+------+------+
6 rows in set (0.00 sec)
mysql>
复制代码
对组合查询结果排序
合并查询
会把各个查询的结果汇总到一块,我们只能对最后总的结果集进行排序,而不能分别对各个查询进行排序。由于最后的结果集展示的列名是第一个查询中给定的列名,所以ORDER BY
子句中指定的排序列也必须是第一个查询中给定的列名,比如这样:
mysql> SELECT m1, n1 FROM t1 UNION SELECT m2, n2 FROM t2 ORDER BY m1 DESC;
+------+------+
| m1 | n1 |
+------+------+
| 4 | d |
| 3 | c |
| 2 | b |
| 1 | a |
+------+------+
4 rows in set (0.00 sec)
mysql>
复制代码
如果我们分别对各个查询进行排序会报错的:
mysql> SELECT m1, n1 FROM t1 ORDER BY m1 DESC UNION SELECT m2, n2 FROM t2 ORDER BY m2;
ERROR 1221 (HY000): Incorrect usage of UNION and ORDER BY
mysql>
复制代码
合并查询注意事项
-
被合并的各个查询的查询对象个数必须相同。
不能一个查询的结果集中有1个列,另一个却有2个列,这会报错的:
mysql> SELECT m1 FROM t1 UNION SELECT m2, n2 FROM t2; ERROR 1222 (21000): The used SELECT statements have a different number of columns mysql> 复制代码
-
查询的结果集中显示的列名将以第一个查询中的列名为准。
-
各个查询语句中的查询列表的类型兼容就可以(也就是说不必完全相同)。
mysql> select m1 from t1 union select n2 from t2; +------+ | m1 | +------+ | 1 | | 2 | | 3 | | b | | c | | d | +------+ 6 rows in set (0.00 sec) mysql> 复制代码
m1
的类型是整数类型,n2
是字符串类型,如果把这两个查询用UNION
合并起来,那么整个结果集的的列的类型将变成字符串类型。虽然这种类型转换是支持的,但是将不同类型的数据放在一个列中容易造成混乱,还是建议大家将各个查询的查询列表置为相同的类型。
小册
本系列专栏都是MySQL入门知识,想看进阶知识可以到小册中查看:MySQL是怎样运行的链接 。小册的内容主要是从小白的角度出发,用比较通俗的语言讲解关于MySQL进阶的一些核心概念,比如记录、索引、页面、表空间、查询优化、事务和锁等,总共的字数大约是三四十万字,配有上百幅原创插图。主要是想降低普通程序员学习MySQL内核的难度,让学习曲线更平滑一点~