阅读 547

MySQL入门系列:查询简介(七)之组合查询

我们前边说的都是单条查询语句,其实多条查询语句的查询结果也可以被合并起来,这种将多个查询的查询结果合并起来的查询方式称为合并查询,或者组合查询

查询列表相同的情况

比如说下边这两条查询语句:

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、n1m2、n2是两个不同的查询列表,但是这两个列组合中m1m2都是整数类型的,n1n2都是字符串类型的,所以也可以把它们的查询结果拼接到一起:

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进阶的一些核心概念,比如记录、索引、页面、表空间、查询优化、事务和锁等,总共的字数大约是三四十万字,配有上百幅原创插图。主要是想降低普通程序员学习MySQL内核的难度,让学习曲线更平滑一点~

关注下面的标签,发现更多相似文章
评论