0


如何使用SQL系列 之 如何在SQL中使用联合(UNION)

引言

许多数据库传播信息在不同的表基于它们的含义和上下文。在检索数据库中保存的数据信息时,经常需要同时引用多个表。

结构化查询语言(SQL)提供了多种从不同表中检索数据的方法,例如集合操作。更具体地说,集合运算符

UNION

在大多数关系数据库系统中都得到了广泛支持。

UNION

操作将两个具有匹配列的查询结果合并为一个。

在本指南中,您将使用“联盟”操作同时从多个表检索数据,然后合并结果。你还将结合使用

UNION

操作符和过滤来对结果进行排序。

前期准备

为了学习本指南,你需要一台运行某种使用SQL的关系数据库管理系统(RDBMS)的计算机。

注意:请注意,许多RDBMS使用它们自己独特的SQL实现。虽然本教程中概述的命令适用于大多数RDBMS,但如果你在MySQL以外的系统上测试它们,确切的语法或输出可能会有所不同。

你还需要一个装载了一些示例数据的数据库和表,可以在其中练习使用相关命令。

连接到MySQL并设置一个示例数据库

如果SQL数据库系统运行在远程服务器上,请从本地设备SSH到服务器:

ssh sammy@your_server_ip

然后打开MySQL服务器提示符,将

==sammy==

替换为你的MySQL用户账户的名称:

mysql -u sammy -p

创建一个名为

bookstore

的数据库:

CREATEDATABASE bookstore;

如果数据库成功创建,您将收到这样的输出:

OutputQuery OK, 1 row affected (0.01 sec)

要选择

bookstore

数据库,运行以下

USE

语句:

USE bookstore;
OutputDatabase changed

选择数据库后,您可以在其中创建示例表。在本指南中,你将使用一个虚构的书店,它既提供图书购买,也提供图书租赁。两个服务都是分开管理的;因此,有关购买和租赁的数据存储在不同的表中。

注意:为了便于学习,本例中的数据库模式被简化了。在实际场景中,表结构将更加复杂,并涉及主键和外键。有关数据库如何组织数据的更多信息,请参阅我们关于理解关系数据库的教程。

第一个表

book_purchases

将包含购买的书籍和购买的顾客的数据。它将包含4列:

  • purchase_id:这一列包含购买标识符,用int数据类型表示。这一列将成为表的主键,每个值将成为对应行的唯一标识符。
  • customer_name:这一列将保存客户的名称,使用varchar数据类型表示,最多30个字符。
  • book_title:这一列将保存购买的图书的标题,使用varchar数据类型表示,最多200个字符。
  • date:使用date数据类型,这一列将保存每次购买的日期。

使用下面的命令创建示例表:

CREATETABLE book_purchases (
    purchase_id int,
    customer_name varchar(30),
    book_title varchar(40),datedate,PRIMARYKEY(purchase_id));

如果输出如下,说明已经创建了第一张表:

OutputQuery OK, 0 rows affected (0.00 sec)

第二个表名为

book_leases

,它将存储有关借阅书籍的信息。它的结构与前一个类似,但租约的特征是两个不同的日期:租约日期和租约持续时间。为了表示这一点,表将包含5列:

  • lease_id:这一列包含租赁标识符,用int数据类型表示。这一列将成为表的主键,每个值将成为对应行的唯一标识符。
  • customer_name:这一列将保存客户的名称,使用varchar数据类型表示,最多30个字符。
  • book_title:这一列将保存借阅书籍的标题,使用varchar数据类型表示,最多200个字符。
  • date_from:使用date数据类型,这一列将保存租约的开始日期。
  • date_to:使用date数据类型,这一列将保存租约的结束日期。

使用下面的命令创建第二个表:

CREATETABLE book_leases (
    lease_id int,
    customer_name varchar(30),
    book_title varchar(40),
    date_from date,
    date_to date,PRIMARYKEY(lease_id));

下面的输出确认了第二个表的创建:

OutputQuery OK, 0 rows affected (0.00 sec)

接下来,通过运行以下

INSERT INTO

操作,加载包含一些示例数据:

INSERTINTO book_purchases
VALUES(1,'sammy','The Picture of Dorian Gray','2022-10-01'),(2,'sammy','Pride and Prejudice','2022-10-04'),(3,'sammy','The Time Machine','2022-09-23'),(4,'bill','Frankenstein','2022-07-23'),(5,'bill','The Adventures of Huckleberry Finn','2022-10-01'),(6,'walt','The Picture of Dorian Gray','2022-04-15'),(7,'walt','Frankenstein','2022-10-13'),(8,'walt','Pride and Prejudice','2022-10-19');
INSERT INTO

操作将向

book_purchases

表中添加8个指定值的购买记录。下面的输出表明已经添加了8行数据:

OutputQuery OK, 8 rows affected (0.00 sec)
Records: 8  Duplicates: 0  Warnings: 0

然后在

book_lease 

表中插入一些示例数据:

INSERTINTO book_leases
VALUES(1,'sammy','Frankenstein','2022-09-14','2022-11-14'),(2,'sammy','Pride and Prejudice','2022-10-01','2022-12-31'),(3,'sammy','The Adventures of Huckleberry Finn','2022-10-01','2022-12-01'),(4,'bill','The Picture of Dorian Gray','2022-09-03','2022-09-18'),(5,'bill','Crime and Punishment','2022-09-27','2022-12-05'),(6,'kim','The Picture of Dorian Gray','2022-10-01','2022-11-15'),(7,'kim','Pride and Prejudice','2022-09-08','2022-11-17'),(8,'kim','The Time Machine','2022-09-04','2022-10-23');

你将收到以下输出,它确认示例数据已被添加:

OutputQuery OK, 8 rows affected (0.00 sec)
Records: 8  Duplicates: 0  Warnings: 0

租赁和购买涉及相似的客户和书籍,这将有助于演示

UNION

操作符的行为。

理解

UNION

操作符的语法

SQL中的

UNION

操作符告诉数据库将通过单独的

SELECT

查询检索到的两个单独的结果集合并为一个结果集,其中包含两个查询返回的行。

注意:数据库不会限制

UNION

SELECT

查询的复杂性。数据检索查询可以包括

JOIN

语句、聚合或子查询。通常,

UNION

用于合并复杂语句的结果。出于教学目的,本指南中的示例将使用

SELECT

查询来关注

UNION

操作符的行为。

下面的例子展示了包含

UNION

操作符的SQL语句的通用语法:

SELECT column1, column2 FROM table1
UNIONSELECT column1, column2 FROM table2;

这个SQL片段以一条从

table1

返回两列的

SELECT

语句开始,接着是

UNION

操作符和第二条

SELECT

语句。第二个

SELECT

查询也返回了两列,但是来自

table2

UNION

关键字告诉数据库获取前面和后面的查询,分别执行它们,然后将它们的结果集连接成一个。整个代码片段,包括

SELECT

查询和它们之间的

UNION

关键字,是一条单独的SQL语句。因此,第一个

SELECT

查询不会以分号结束,它只出现在整个语句之后。

举个例子,假设你想列出购买或租用图书的所有客户。购买记录保存在

book_purchases

表中,而租赁记录保存在

book_leases

表中。运行以下查询:

SELECT customer_name FROM book_purchases
UNIONSELECT customer_name FROM book_leases;

下面是这个查询的结果集:

Output+---------------+
| customer_name |
+---------------+
| sammy         || bill          || walt          || kim           |
+---------------+
4 rows inset(0.000 sec)

这个输出表明Sammy、Bill、Walt和Kim在某个时间点购买或租了书。要理解这个结果集是如何生成的,请尝试分别执行两个

SELECT

语句:一次针对purchase,一次针对lease。

运行下面的查询来返回购买图书的顾客:

SELECT customer_name FROM book_purchases;

下面的输出将打印到屏幕上:

Output+---------------+
| customer_name |
+---------------+
| sammy         || sammy         || sammy         || bill          || bill          || walt          || walt          || walt          |
+---------------+
8 rows inset(0.000 sec)

Sammy, Bill和 Walt 购买书籍,但是Kim 没有。

接下来,运行查询来返回租书的顾客:

SELECT customer_name FROM book_leases;

下面的输出将打印到屏幕上:

Output+---------------+
| customer_name |
+---------------+
| sammy         || sammy         || sammy         || bill          || bill          || kim           || kim           || kim           |
+---------------+
8 rows inset(0.000 sec)

租赁表指Sammy, Bill和Kim,但Walt从未借的书。通过组合两个答案,您可以得到租赁和购买的数据。

使用

UNION

和单独执行两个查询之间的重要区别是,

UNION

除了合并结果之外,还删除了重复的值:在结果中没有重复的客户名称。

为了使用

UNION

正确地合并两个独立查询的结果,两个查询都应该返回相同格式的结果。有些不一致会导致数据库引擎错误,而有些则会给出与查询意图不匹配的结果。

考虑下面两个例子:

列计数不匹配的UNION

试着在返回单列的

SELECT

语句和返回两列的

UNION

语句之间执行:

SELECT purchase_id, customer_name FROM book_purchases
UNIONSELECT customer_name FROM book_leases;

数据库服务器将返回一个错误:

OutputThe used SELECT statements have a different number of columns

无法对具有不同列数的结果集执行

UNION

操作。

列顺序不匹配的UNION

试着在两个返回相同值但顺序不同的

SELECT

语句之间执行

UNION

SELECT customer_name, book_title FROM book_purchases
UNIONSELECT book_title, customer_name FROM book_leases;

数据库服务器不会返回错误,但结果集不会是正确的:

Output+------------------------------------+------------------------------------+
| customer_name                      | book_title                         |
+------------------------------------+------------------------------------+
| sammy                              | The Picture of Dorian Gray         || sammy                              | Pride and Prejudice                || sammy                              | The Time Machine                   || bill                               | Frankenstein                       || bill                               | The Adventures of Huckleberry Finn || walt                               | The Picture of Dorian Gray         || walt                               | Frankenstein                       || walt                               | Pride and Prejudice                || Frankenstein                       | sammy                              || Pride and Prejudice                | sammy                              || The Adventures of Huckleberry Finn | sammy                              || The Picture of Dorian Gray         | bill                               || Crime and Punishment               | bill                               || The Picture of Dorian Gray         | kim                                || Pride and Prejudice                | kim                                || The Time Machine                   | kim                                |
+------------------------------------+------------------------------------+
16 rows inset(0.000 sec)

在这个例子中,

UNION

操作将第一个查询的第一列与第二个查询的第一列合并,并对第二个列执行相同的操作,将客户姓名和图书名称混合在一起。

使用

WHERE

子句并与

UNION

一起排序

在前面的例子中,合并了表示两个对应表中所有行的结果集。通常,你需要在合并结果之前过滤行。用

UNION

操作符合并的

SELECT

语句可以使用

WHERE

子句来完成。

假设你想知道Sammy在你的书店的帮助下读了哪些书,无论是通过购买还是租赁。运行以下查询:

SELECT book_title FROM book_purchases
WHERE customer_name ='Sammy'UNIONSELECT book_title FROM book_leases
WHERE customer_name ='Sammy';

两个

SELECT

查询都包含

WHERE

子句,它从两个不同的表中过滤数据,只包含

Sammy

的purchase和lease。此查询的结果集将打印如下:

Output+------------------------------------+
| book_title                         |
+------------------------------------+
| The Picture of Dorian Gray         || Pride and Prejudice                || The Time Machine                   || Frankenstein                       || The Adventures of Huckleberry Finn |
+------------------------------------+
5 rows inset(0.000 sec)

再一次,

UNION

确保结果列表中没有重复的结果。你可以使用

WHERE

子句来限制在

SELECT

查询中返回哪些行,或者只返回其中的一行。此外,

WHERE

子句可以引用两个语句中的不同列和条件。

通过

UNION

操作返回的结果没有任何特定的顺序。要改变这一点,你可以利用

ORDER BY

子句。排序是在最终合并的结果上执行的,而不是在单个查询上执行的。

在检索到Sammy购买或租赁的所有图书后,要对书名按字母顺序排序,执行以下查询:

SELECT book_title FROM book_purchases
WHERE customer_name ='Sammy'UNIONSELECT book_title FROM book_leases
WHERE customer_name ='Sammy'ORDERBY book_title;

下面的输出将打印到屏幕上:

Output+------------------------------------+
| book_title                         |
+------------------------------------+
| Frankenstein                       || Pride and Prejudice                || The Adventures of Huckleberry Finn || The Picture of Dorian Gray         || The Time Machine                   |
+------------------------------------+
5 rows inset(0.001 sec)

这一次,返回的结果是基于包含两个

SELECT

查询合并结果的

book_title

列的顺序。

使用

UNION ALL

来保留副本

如前面的例子所示,

UNION

操作符会自动从结果中删除重复的行。然而,有时这种行为并不是您期望或打算通过查询实现的。例如,假设您感兴趣的书籍,购买或租赁10月1日,2022年。要取得这些标题,可以像之前一样使用类似的例子:

SELECT book_title FROM book_purchases
WHEREdate='2022-10-01'UNIONSELECT book_title FROM book_leases
WHERE date_from ='2022-10-01'ORDERBY book_title;

You will get the following results:

Output+------------------------------------+
| book_title                         |
+------------------------------------+
| Pride and Prejudice                || The Adventures of Huckleberry Finn || The Picture of Dorian Gray         |
+------------------------------------+
3 rows inset(0.001 sec)

归还的书名是正确的,但结果不会告诉你这些书是只买的、只租的,还是两者都有。如果有些书同时购买和租赁,它们的书名将同时出现在

book_purchase

book_lease

表中。然而,由于

UNION

删除了重复的行,这些信息在结果中丢失了。

幸运的是,SQL有办法改变这种行为,保留重复的行。你可以使用

UNION ALL

操作符来合并两个查询的结果,而不会删除重复的行。

UNION ALL

的工作原理与

UNION

类似,但当相同的值出现多次时,ALL将出现在结果中。

运行相同的查询,但将

UNION

更改为

UNION ALL

SELECT book_title FROM book_purchases
WHEREdate='2022-10-01'UNIONALLSELECT book_title FROM book_leases
WHERE date_from ='2022-10-01'ORDERBY book_title;

这一次,得到的列表变长了:

Output+------------------------------------+
| book_title                         |
+------------------------------------+
| Pride and Prejudice                || The Adventures of Huckleberry Finn || The Adventures of Huckleberry Finn || The Picture of Dorian Gray         || The Picture of Dorian Gray         |
+------------------------------------+
5 rows inset(0.000 sec)

《The Adventures of Huckleberry Finn》和《The Picture of Dorian Gray》这两本书在结果集中出现了两次。这意味着这些标题同时出现在

book_purchase 

book_lease 

表中。对于重复的条目,您可以假设它们在当天已经被租赁和购买。

根据你是想删除还是保留重复项,你可以在

UNION

UNION ALL

操作符之间进行选择,它们可以互换使用。

注意:执行工会所有的速度比执行“联盟”,作为数据库不需要对重复扫描结果集。如果你正在合并两个

SELECT

查询的结果,并且你知道它们不会包含任何重复的行,那么在更大的数据集上使用

UNION ALL

可以带来明显的性能提升。

总结

按照本指南,你可以使用

UNION

UNION ALL

操作从多个表中检索数据。你还使用了

WHERE

子句来过滤结果,并使用

ORDER BY

子句来对结果进行排序。最后,你了解了如果

SELECT

语句产生不同的数据格式,可能出现的错误和意外行为。

虽然这里包含的命令应该适用于大多数关系数据库,但请注意,每个SQL数据库都使用自己独特的语言实现。

标签: sql 数据库 mysql

本文转载自: https://blog.csdn.net/QIU176161650/article/details/132697204
版权归原作者 CHQIUU 所有, 如有侵权,请联系我们删除。

“如何使用SQL系列 之 如何在SQL中使用联合(UNION)”的评论:

还没有评论