美文网首页
SQL操作指南八(集合运算)

SQL操作指南八(集合运算)

作者: 了不起的树懒 | 来源:发表于2018-11-11 17:22 被阅读0次

    表的加减法

    • 表的加法——UNION
      首先创建一个名称为shop_list2的表便于代码演示,如下:
    +---------+-----------+-----------+------------+-----------+---------------+
    | shop_id | shop_name | shop_type | sell_price | buy_price | register_date |
    +---------+-----------+-----------+------------+-----------+---------------+
    | 0001    | T恤衫     | 衣服      |       1000 |       500 | 2008-09-20    |
    | 0002    | 打孔器    | 工具      |        500 |       320 | 2008-09-11    |
    | 0003    | 运动T恤   | 衣服      |       4000 |      2800 | NULL          |
    | 0009    | 手套      | 衣服      |        800 |       500 | NULL          |
    | 0010    | 水壶      | 厨房用具  |       2000 |      1700 | 2009-09-20    |
    +---------+-----------+-----------+------------+-----------+---------------+
    

    接下来,将两张表相加:

    SELECT shop_id,shop_name
    FROM shop_list
    UNION
    SELECT shop_id,shop_name
    FROM shop_list2;
    +---------+-----------+
    | shop_id | shop_name |
    +---------+-----------+
    | 0001    | T恤衫     |
    | 0002    | 打孔器    |
    | 0003    | 运动T恤   |
    | 0004    | 菜刀      |
    | 0005    | 砧板      |
    | 0006    | 扳手      |
    | 0009    | 手套      |
    | 0010    | 水壶      |
    +---------+-----------+
    

    由表可以看出UNION集合就是并集,该集合运算符会除去重复的记录。

    • 集合运算符的注意事项
      1.作为运算对象的记录列数必须相同;
      当两张表的列数不相同时,UNION是不能将两张表相加的。
      2.作为运算对象的记录中列的类型必须一致;
      不同类型的数据肯定不能存放在同一列的,如果非要相加的话,可以尝试类型转换。
      3.可以使用任何SELECT 语句,但ORDER BY子句只能在最后使用一次;
      示例:
    SELECT shop_id,shop_name
    FROM shop_list
    WHERE shop_type = '厨房用具'
    UNION
    SELECT shop_id,shop_name
    FROM shop_list2
    WHERE shop_type='厨房用具'
    ORDER BY shop_id;
    +---------+-----------+
    | shop_id | shop_name |
    +---------+-----------+
    | 0004    | 菜刀      |
    | 0005    | 砧板      |
    | 0010    | 水壶      |
    +---------+-----------+
    
    • 包含重复行的集合运算——ALL选项
      UNION的结果没有包含重复行,那么只需要在UNION后面加上ALL关键字的结果就是可以显示所有行,包括重复行。
    SELECT shop_id,shop_name
    FROM shop_list
    UNION ALL
    SELECT shop_id,shop_name
    FROM shop_list2;
    +---------+-----------+
    | shop_id | shop_name |
    +---------+-----------+
    | 0001    | T恤衫     |
    | 0002    | 打孔器    |
    | 0003    | 运动T恤   |
    | 0004    | 菜刀      |
    | 0005    | 砧板      |
    | 0006    | 扳手      |
    | 0001    | T恤衫     |
    | 0002    | 打孔器    |
    | 0003    | 运动T恤   |
    | 0009    | 手套      |
    | 0010    | 水壶      |
    +---------+-----------+
    
    • 选取表中公共部分——INTERSECT
      INTERSECT即为获取两个表的交集。
    SELECT shop_id,shop_name
    FROM shop_list
    INTERSECT
    SELECT shop_id,shop_name
    FROM shop_list2
    ORDER BY shop_id;
    

    MySQL暂时不支持INTERSECT用法。

    • 表的减法——EXCEPT
      EXCEPT即为表1减取与表2中重复的部分剩下的记录,用法与UNION相同。
    SELECT shop_id,shop_name
    FROM shop_list
    EXCEPT
    SELECT shop_id,shop_name
    FROM shop_list2
    ORDER BY shop_id;
    

    Oracle不适用EXCEPT,其拥有特有的MINUS代替EXCEPT,MySQL暂时不支持EXCEPT这种用法。

    联结(以列为单位对表进行联结)

    前面学习的集合运算都是造成了行的变化,而联结的作用就是进行列的变化。

    • 内联结——INNER JOIN
      演示代码将会用到两张表:
    +---------+-----------+-----------+------------+-----------+---------------+
    | shop_id | shop_name | shop_type | sell_price | buy_price | register_date |
    +---------+-----------+-----------+------------+-----------+---------------+
    | 0001    | T恤衫     | 衣服      |       2000 |       500 | 2009-09-20    |
    | 0002    | 打孔器    | 工具      |        600 |       100 | 2009-09-20    |
    | 0003    | 运动T恤   | 衣服      |       3000 |      2800 | 2009-09-20    |
    | 0004    | 菜刀      | 厨房用具  |       6000 |      2800 | 2009-09-20    |
    | 0005    | 砧板      | 厨房用具  |       2000 |      1299 | 2009-09-20    |
    | 0006    | 扳手      | 工具      |       3000 |      1500 | 2009-09-20    |
    +---------+-----------+-----------+------------+-----------+---------------+
    
    +---------+-----------+---------+--------+
    | area_id | area_name | shop_id | number |
    +---------+-----------+---------+--------+
    | 000A    | 北京      | 0001    |     30 |
    | 000A    | 北京      | 0002    |     50 |
    | 000A    | 北京      | 0003    |     15 |
    | 000B    | 上海      | 0002    |     30 |
    | 000B    | 上海      | 0003    |    120 |
    | 000B    | 上海      | 0004    |     20 |
    | 000B    | 上海      | 0006    |     10 |
    | 000B    | 上海      | 0007    |     40 |
    | 000C    | 重庆      | 0003    |     20 |
    | 000C    | 重庆      | 0004    |     50 |
    | 000C    | 重庆      | 0006    |     90 |
    | 000C    | 重庆      | 0007    |     70 |
    | 000D    | 杭州      | 0001    |    100 |
    +---------+-----------+---------+--------+
    

    如上表,两张表的列可以分为如下两类:
    1.两张表中有包含相同的列→shop_id;
    2.只存在与一张表内的列→除shop_id以外的列;
    所谓联结,就是"以1中的的列作为桥梁,将2中的满足其他条件的列汇集到同一结果中"。
    我们可以试着从shop_list中取出shop_name和sell_price与shop_area中的内容进行结合。

    SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
    FROM shop_area AS SA JOIN shop_list AS SL
    ON SA.shop_id=SL.shop_id;
    +---------+-----------+---------+-----------+------------+
    | area_id | area_name | shop_id | shop_name | sell_price |
    +---------+-----------+---------+-----------+------------+
    | 000A    | 北京      | 0001    | T恤衫     |       2000 |
    | 000A    | 北京      | 0002    | 打孔器    |        600 |
    | 000A    | 北京      | 0003    | 运动T恤   |       3000 |
    | 000B    | 上海      | 0002    | 打孔器    |        600 |
    | 000B    | 上海      | 0003    | 运动T恤   |       3000 |
    | 000B    | 上海      | 0004    | 菜刀      |       6000 |
    | 000B    | 上海      | 0006    | 扳手      |       3000 |
    | 000C    | 重庆      | 0003    | 运动T恤   |       3000 |
    | 000C    | 重庆      | 0004    | 菜刀      |       6000 |
    | 000C    | 重庆      | 0006    | 扳手      |       3000 |
    | 000D    | 杭州      | 0001    | T恤衫     |       2000 |
    +---------+-----------+---------+-----------+------------+
    

    联结需要注意的点:
    1.FROM子句:因为联结需要用到两张或多张表,使用关键字INNER JOIN就可以把两张表联结在一起,虽然使用别名不是必须的,但是过长的表名会影响可读性,所以尽量使用别名。
    2.ON子句:ON后面记载的是联结条件,我们可以在ON后面指定联结所使用的列(联结键),ON子句在进行联结时是必不可少的,并且必须书写在FROM和WHERE之间。
    3.SELECT子句:由于使用多张表,所以列的归属会非常混乱。所以为了避免混淆列的归属,可以使用<表的别名>.<列名>的方法书写。

    内联结和WHERE子句结合使用
    如果不想了解所有地区的情况,只想了解上海地区的情况,可以在联结语句中加入WHERE来限定条件。

    SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
    FROM shop_area AS SA JOIN shop_list AS SL
    ON SA.shop_id=SL.shop_id
    WHERE SA.area_id='000B';
    +---------+-----------+---------+-----------+------------+
    | area_id | area_name | shop_id | shop_name | sell_price |
    +---------+-----------+---------+-----------+------------+
    | 000B    | 上海      | 0002    | 打孔器    |        600 |
    | 000B    | 上海      | 0003    | 运动T恤   |       3000 |
    | 000B    | 上海      | 0004    | 菜刀      |       6000 |
    | 000B    | 上海      | 0006    | 扳手      |       3000 |
    +---------+-----------+---------+-----------+------------+
    

    像这样的联结运算结果,不仅可以使用WHERE子句,还能使用GROUP BY、HAVING、ORDER BY等。准确地说,可以完全把它看作一张新的表。

    • 外联结——OUTER JOIN
      外联结也是通过ON子句使用联结键将两张表进行联结,同时从两张表中选出相应的列,基本使用方法没有改变,但是结果却有所不同。
    SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price
    FROM shop_area AS SA RIGHT OUTER JOIN shop_list AS SL
    ON SA.shop_id=SL.shop_id;
    +---------+-----------+---------+-----------+------------+
    | area_id | area_name | shop_id | shop_name | sell_price |
    +---------+-----------+---------+-----------+------------+
    | 000A    | 北京      | 0001    | T恤衫     |       2000 |
    | 000A    | 北京      | 0002    | 打孔器    |        600 |
    | 000A    | 北京      | 0003    | 运动T恤   |       3000 |
    | 000B    | 上海      | 0002    | 打孔器    |        600 |
    | 000B    | 上海      | 0003    | 运动T恤   |       3000 |
    | 000B    | 上海      | 0004    | 菜刀      |       6000 |
    | 000B    | 上海      | 0006    | 扳手      |       3000 |
    | 000C    | 重庆      | 0003    | 运动T恤   |       3000 |
    | 000C    | 重庆      | 0004    | 菜刀      |       6000 |
    | 000C    | 重庆      | 0006    | 扳手      |       3000 |
    | 000D    | 杭州      | 0001    | T恤衫     |       2000 |
    | NULL    | NULL      | NULL    | 砧板      |       2000 |
    +---------+-----------+---------+-----------+------------+
    

    即使联结键在两张表中没有都存在,该行还是会进行联结,不存在的数据以NULL显示。
    外联结要点:
    1.选取出单张表中的全部的信息:只要数据存在于某一个表中,就能够读取出来。
    2.外联结的主表:外联结中的主表很重要,哪张为主表,那么最总的结果中会包含这张主表内的所有数据。指定主表的关键字是LEFT和RIGTH,使用LEFT时FROM子句写在左侧的为主表,反之右侧为主表。

    • 3张以上表的联结
      原则上,表的联结对表的数量没有限制。
      首先创建一张名称为storage的表作为第三张需要联结的表:
    +------------+---------+----------------+
    | storage_id | shop_id | storage_number |
    +------------+---------+----------------+
    | S001       | 0001    |              0 |
    | S001       | 0002    |            120 |
    | S001       | 0003    |            200 |
    | S001       | 0004    |              3 |
    | S001       | 0005    |              0 |
    | S001       | 0006    |             99 |
    | S001       | 0007    |            999 |
    | S001       | 0008    |            200 |
    | S002       | 0001    |             10 |
    | S002       | 0002    |             25 |
    | S002       | 0003    |             34 |
    | S002       | 0004    |             19 |
    | S002       | 0005    |             99 |
    | S002       | 0006    |              0 |
    | S002       | 0007    |              0 |
    | S002       | 0008    |             18 |
    +------------+---------+----------------+
    

    对第三张表进行联结

    SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name,SL.sell_price,ST.storage_number
    FROM shop_area AS SA INNER JOIN shop_list AS SL
    ON SA.shop_id=SL.shop_id
    INNER JOIN storage AS ST
    ON SA.shop_id=ST.shop_id
    WHERE ST.storage_id='S001';
    +---------+-----------+---------+-----------+------------+----------------+
    | area_id | area_name | shop_id | shop_name | sell_price | storage_number |
    +---------+-----------+---------+-----------+------------+----------------+
    | 000A    | 北京      | 0001    | T恤衫     |       2000 |              0 |
    | 000A    | 北京      | 0002    | 打孔器    |        600 |            120 |
    | 000A    | 北京      | 0003    | 运动T恤   |       3000 |            200 |
    | 000B    | 上海      | 0002    | 打孔器    |        600 |            120 |
    | 000B    | 上海      | 0003    | 运动T恤   |       3000 |            200 |
    | 000B    | 上海      | 0004    | 菜刀      |       6000 |              3 |
    | 000B    | 上海      | 0006    | 扳手      |       3000 |             99 |
    | 000C    | 重庆      | 0003    | 运动T恤   |       3000 |            200 |
    | 000C    | 重庆      | 0004    | 菜刀      |       6000 |              3 |
    | 000C    | 重庆      | 0006    | 扳手      |       3000 |             99 |
    | 000D    | 杭州      | 0001    | T恤衫     |       2000 |              0 |
    +---------+-----------+---------+-----------+------------+----------------+
    

    可以简单地理解成,将1,2两张表先联结,然后将重新生成的表再与表3进行联结。

    • 交叉联结——CROSS JOIN
    SELECT SA.area_id,SA.area_name,SA.shop_id,SL.shop_name
    FROM shop_area AS SA CROSS JOIN shop_list AS SL;
    +---------+-----------+---------+-----------+
    | area_id | area_name | shop_id | shop_name |
    +---------+-----------+---------+-----------+
    | 000A    | 北京      | 0001    | T恤衫     |
    | 000A    | 北京      | 0001    | 打孔器    |
    | 000A    | 北京      | 0001    | 运动T恤   |
    | 000A    | 北京      | 0001    | 菜刀      |
    | 000A    | 北京      | 0001    | 砧板      |
    | 000A    | 北京      | 0001    | 扳手      |
    | 000A    | 北京      | 0002    | T恤衫     |
    | 000A    | 北京      | 0002    | 打孔器    |
    | 000A    | 北京      | 0002    | 运动T恤   |
    | 000A    | 北京      | 0002    | 菜刀      |
    | 000A    | 北京      | 0002    | 砧板      |
    | 000A    | 北京      | 0002    | 扳手      |
    | 000A    | 北京      | 0003    | T恤衫     |
    | 000A    | 北京      | 0003    | 打孔器    |
    | 000A    | 北京      | 0003    | 运动T恤   |
    | 000A    | 北京      | 0003    | 菜刀      |
    | 000A    | 北京      | 0003    | 砧板      |
    | 000A    | 北京      | 0003    | 扳手      |
    | 000B    | 上海      | 0002    | T恤衫     |
    | 000B    | 上海      | 0002    | 打孔器    |
    | 000B    | 上海      | 0002    | 运动T恤   |
    | 000B    | 上海      | 0002    | 菜刀      |
    | 000B    | 上海      | 0002    | 砧板      |
    | 000B    | 上海      | 0002    | 扳手      |
    | 000B    | 上海      | 0003    | T恤衫     |
    | 000B    | 上海      | 0003    | 打孔器    |
    | 000B    | 上海      | 0003    | 运动T恤   |
    | 000B    | 上海      | 0003    | 菜刀      |
    | 000B    | 上海      | 0003    | 砧板      |
    | 000B    | 上海      | 0003    | 扳手      |
    | 000B    | 上海      | 0004    | T恤衫     |
    | 000B    | 上海      | 0004    | 打孔器    |
    | 000B    | 上海      | 0004    | 运动T恤   |
    | 000B    | 上海      | 0004    | 菜刀      |
    | 000B    | 上海      | 0004    | 砧板      |
    | 000B    | 上海      | 0004    | 扳手      |
    | 000B    | 上海      | 0006    | T恤衫     |
    | 000B    | 上海      | 0006    | 打孔器    |
    | 000B    | 上海      | 0006    | 运动T恤   |
    | 000B    | 上海      | 0006    | 菜刀      |
    | 000B    | 上海      | 0006    | 砧板      |
    | 000B    | 上海      | 0006    | 扳手      |
    | 000B    | 上海      | 0007    | T恤衫     |
    | 000B    | 上海      | 0007    | 打孔器    |
    | 000B    | 上海      | 0007    | 运动T恤   |
    | 000B    | 上海      | 0007    | 菜刀      |
    | 000B    | 上海      | 0007    | 砧板      |
    | 000B    | 上海      | 0007    | 扳手      |
    | 000C    | 重庆      | 0003    | T恤衫     |
    | 000C    | 重庆      | 0003    | 打孔器    |
    | 000C    | 重庆      | 0003    | 运动T恤   |
    | 000C    | 重庆      | 0003    | 菜刀      |
    | 000C    | 重庆      | 0003    | 砧板      |
    | 000C    | 重庆      | 0003    | 扳手      |
    | 000C    | 重庆      | 0004    | T恤衫     |
    | 000C    | 重庆      | 0004    | 打孔器    |
    | 000C    | 重庆      | 0004    | 运动T恤   |
    | 000C    | 重庆      | 0004    | 菜刀      |
    | 000C    | 重庆      | 0004    | 砧板      |
    | 000C    | 重庆      | 0004    | 扳手      |
    | 000C    | 重庆      | 0006    | T恤衫     |
    | 000C    | 重庆      | 0006    | 打孔器    |
    | 000C    | 重庆      | 0006    | 运动T恤   |
    | 000C    | 重庆      | 0006    | 菜刀      |
    | 000C    | 重庆      | 0006    | 砧板      |
    | 000C    | 重庆      | 0006    | 扳手      |
    | 000C    | 重庆      | 0007    | T恤衫     |
    | 000C    | 重庆      | 0007    | 打孔器    |
    | 000C    | 重庆      | 0007    | 运动T恤   |
    | 000C    | 重庆      | 0007    | 菜刀      |
    | 000C    | 重庆      | 0007    | 砧板      |
    | 000C    | 重庆      | 0007    | 扳手      |
    | 000D    | 杭州      | 0001    | T恤衫     |
    | 000D    | 杭州      | 0001    | 打孔器    |
    | 000D    | 杭州      | 0001    | 运动T恤   |
    | 000D    | 杭州      | 0001    | 菜刀      |
    | 000D    | 杭州      | 0001    | 砧板      |
    | 000D    | 杭州      | 0001    | 扳手      |
    +---------+-----------+---------+-----------+
    

    交叉联结时,无法使用ON子句,这是因为交叉联结是对两张表内全部记录进行交叉组合,因此结果中记录数通常是两张表的行数乘积。

    相关文章

      网友评论

          本文标题:SQL操作指南八(集合运算)

          本文链接:https://www.haomeiwen.com/subject/psmxfqtx.html