组合查询

   组合查询具有两个或多个 SELECT 语句,由负责结合两个查询的操作符组成。本节介绍如何使用操作符 union、intersect、minus 把多个 SQL 查询组合为一个。
   使用规则:在使用组合查询操作符时,每个 SELECT 语句里必须选择同样数量的字段、同样数量的字段表达式、同样的数据类型、同样的次序——但长度不必一样。
   本节的例子使用的是 learnsql 数据库里的雇员表、雇员工资表、顾客信息表和订单表。
一、并集 union
    1、union
     union 操作符可以组合两个或多个 SELECT 语句的结果,不包含重复的记录。如果某行的输出存在于一个查询结果里,其他查询结果同一行的记录就不会再输出了。
     语法:
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
         UNION
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
     例1:查询雇员 ID: 
        SELECT EMP_ID FROM EMPLOYEE_TBL;
        结果:
         EMP_ID
         213764555
         220984332
         311549902
         313782439
         442346889
         443679012
     在 EMPLOYEE_TBL 表里 EMP_ID 有6行记录。
     SELECT EMP_ID FROM EMPLOYEE_PAY_TBL;
    结果:
         EMP_ID
         442346889
         443679012
         313782439
         213764555
         311549902
    在 EMPLOYEE_PAY_TBL 表里 EMP_ID 有5行记录。
    SELECT EMP_ID FROM EMPLOYEE_TBL
    UNION
    SELECT EMP_ID FROM EMPLOYEE_PAY_TBL;
    结果: 
         EMP_ID
         213764555
         220984332
         311549902
         313782439
         442346889
         443679012
        雇员 ID 在两个表里都存在,但在结果里只出现一次。
    2、union all
        union all 操作符可以组合两个 SELECT 语句的结果,并且包含重复的结果。它与 union 基本上是一样的,只是一个返回重复的结果,一个不返回。
        语法:
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
         UNION ALL
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
        例2:下面这个语句返回全部雇员 ID,并且包含重复的记录:
         SELECT EMP_ID FROM EMPLOYEE_TBL
         UNION ALL
         SELECT EMP_ID FROM EMPLOYEE_PAY_TBL;
        结果: 
         EMP_ID
         213764555
         220984332
         311549902
         313782439
         442346889
         443679012
         442346889
         443679012
         313782439
         213764555
         311549902
     因为 union all 操作符会返回重复的数据,所以这个查询返回了11条记录。
二、交集 intersect
       intersect 可以组合两个 SELECT 语句,但只返回两个语句里一样的记录。
       语法:
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
         INTERSECT
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
        例3:查询具有订单的顾客的 ID:
         SELECT CUST_ID FROM CUSTOMER_TBL;
        结果:
         CUST_ID
         090
         109
         12
         21
         221
         232
         287
         288
         333
         345
         43
         432
         560
         590
         610
         715
        返回16条记录。
         SELECT CUST_ID FROM ORDERS_TBL;
        结果:
         CUST_ID
         090
         12
         232
         287
         43
         432
        返回6条记录。
        SELECT CUST_ID FROM CUSTOMER_TBL
        INTERSECT 
        SELECT CUST_ID FROM ORDERS_TBL;
        结果:
         CUST_ID
         090
         12
         232
         287
         43
         432
        返回两表里相同的6条记录。
三、差集 minus
        MINUS 操作符组合两个 SELECT 语句,返回第一个语句里有但第二个语句里没有的记录。
        语法:
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
         MINUS
         SELECT 列名
         FROM 表名
         [ WHERE . . . ]
        例4:查询没有订单的顾客的 ID:
         SELECT CUST_ID FROM CUSTOMER_TBL
         MINUS
         SELECT CUST_ID FROM ORDERS_TBL;
        结果: 
         CUST_ID
         109
         21
         221
         288
         333
         345
         560
         590
         610
         715
    返回第一个表里有但第二个表里没有的10条记录。
四、小结
    组合查询可以让多个查询一起返回一个统一的数据集。本节介绍的组合操作符包括 union、union all、intersect 和 minus。union 返回两个查询的全部结果,不管数据是否重复。intersect 返回两个查询结果中一样的记录。minus 返回一个查询结果中不存在于另一个查询结果的记录。组合查询具有很大的灵活性,能够满足各种查询的要求。如果不使用组合查询,可能需要很复杂的查询语句才能达到同样的结果。
    使用组合查询时要小心。在使用 intersect 操作符时,如果第一个查询的 SELECT 语句有问题,就可能会得到不正确或不完整的数据。在使用 union 和union all 操作符时,要考虑是否需要返回重复的数据。而使用 minus 操作符时,我们要考虑是否需要不存在于第二个查询里的数据。组合查询里的错误组合操作符或单个查询的次序有误都会导致返回不正确的数据。
    如果两个查询语句的字段名不同,第一个查询决定了输出的字段名称。
    另外,MySQL 不支持 INTERSECT 和 MINUS,使用时要加以注意,可以使用其它替代方法。

【参考资料】
  W3SChool 在线SQL教程   http://www.w3SChool.com.cn/sql/sql_union.asp  SQL UNION 和 UNION ALL 操作符 

课后练习:
        1. 匹配操作符与相应的描述:
                 描述     操作符
         a. 显示重复记录    union
         b. 返回第一个查询里有但第二个查询里没有的结果 intersect
         c. 返回不重复的记录    union all
         d. 返回第一个查询里与第二个查询匹配的结果 minus
        2. 使用数据库 learnsql 里的表 CUSTOMER_TBL 和 ORDERS_TBL 编写组合查询:
         1)返回下了订单的顾客。
         2)返回没有下订单的顾客。