task 4:集合运算

4.1 表的加减法

4.1.1 什么是集合运算

在这里插入图片描述

4.1.2 表的加法—UNION

4.1.2.1 UNION

UNION相当于是求并集的运算,可以对两张表,也可以对同一张表~~
UNION会除去重复的记录!!!

#两张表
SELECT product_id, product_name
  FROM product
 UNION
SELECT product_id, product_name
  FROM product2;

在这里插入图片描述
同一张表~~
练习题:假设连锁店想要增加毛利率超过 50%或者售价低于 800 的货物的存货量, 请使用 UNION 对分别满足上述两个条件的商品的查询结果求并集.

SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM product 
 WHERE sale_price<800
  
 UNION
 
SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM product 
 WHERE sale_price>1.5*purchase_price;

不使用UNION

SELECT  product_id,product_name,product_type
       ,sale_price,purchase_price
  FROM product 
 WHERE sale_price < 800 
    OR sale_price > 1.5 * purchase_price;

4.1.2.2 UNION 与 OR 谓词

确实, 对于同一个表的两个不同的筛选结果集, 使用 UNION 对两个结果集取并集, 和把两个子查询的筛选条件用 OR 谓词连接, 会得到相同的结果, 但倘若要将两个不同的表中的结果合并在一起, 就不得不使用 UNION 了,而且, 即便是对于同一张表, 有时也会出于查询效率方面的因素来使用 UNION。

练习题:分别使用 UNION 或者 OR 谓词,找出毛利率不足 30%或毛利率未知的商品.

-- 使用 OR 谓词
SELECT * 
  FROM product 
 WHERE sale_price / purchase_price < 1.3 
    OR sale_price / purchase_price IS NULL;
-- 使用 UNION
SELECT * 
  FROM product 
 WHERE sale_price / purchase_price < 1.3
 
 UNION
SELECT * 
  FROM product 
 WHERE sale_price / purchase_price IS NULL;

4.1.2.3 包含重复行的集合运算 UNION ALL

union all可以保留重复行!!!用法同上union

4.1.2.4 bag 模型与 set模型

是否允许元素重复导致了 set 和 bag 的并交差等运算都存在一些区别. 以 bag 的交为例, 由于 bag 允许元素重复出现, 对于两个 bag, 他们的并运算会按照: 1.该元素是否至少在一个 bag 里出现过, 2.该元素在两个 bag 中的最大出现次数 这两个方面来进行计算. 因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的并就等于 {1,1,1,2,2,3,4,5,6,7,8}

4.1.2.5 隐式类型转换

通常来说, 我们会把类型完全一致, 并且代表相同属性的列使用 UNION 合并到一起显示, 但有时候, 即使数据类型不完全相同, 也会通过隐式类型转换来将两个类型不同的列放在一列里显示,时间日期类型和字符串,数值以及缺失值均能兼容。
SYSDATE()函数可以返回当前日期时间

4.1.3 MySQL 8.0 不支持交运算INTERSECT

集合的交也就是两个集合的公共部分

4.1.3.1 bag的交运算

对于两个 bag, 他们的交运算会按照: 1.该元素是否同时属于两个 bag, 2.该元素在两个 bag 中的最小出现次数这两个方面来进行计算. 因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的交运算结果就等于 {1,1,2}

4.1.4 差集,补集与表的减法

4.1.4.1 MySQL 8.0 不支持EXCEPT运算

可用 not in 来实现except的功能

4.1.4.2 EXCEPT 与 NOT 谓词

练习题: 使用NOT谓词进行集合的减法运算, 求出product表中, 售价高于2000,但利润低于30%的商品, 结果应该如下表所示.
在这里插入图片描述

SELECT * 
  FROM product
 WHERE sale_price > 2000 
   AND product_id NOT IN (SELECT product_id 
                            FROM product 
                           WHERE sale_price >= 1.3*purchase_price)

4.1.4.3 EXCEPT ALL 与 bag 的差

对于两个 bag, 他们的差运算会按照:
1.该元素是否属于作为被减数的 bag,
2.该元素在两个 bag 中的出现次数

这两个方面来进行计算. 只有属于被减数的bag的元素才参与EXCEP ALL运算, 并且差bag中的次数,等于该元素在两个bag的出现次数之差(差为零或负数则不出现). 因此对于 A = {1,1,1,2,3,5,7}, B = {1,1,2,2,4,6,8} 两个 bag, 它们的差就等于 {1,3,5,7}.

4.1.4.4 IN TERSECT 与 AND 谓词

对于同一个表的两个查询结果而言, 他们的交INTERSECT实际上可以等价地将两个查询的检索条件用AND谓词连接来实现

4.1.5 对称差

两个集合的对称差等于 A-B并上B-A, 因此实践中可以用这个思路来求对称差
练习题:使用product表和product2表的对称差来查询哪些商品只在其中一张表, 结果类似于:
在这里插入图片描述

-- 使用 NOT IN 实现两个表的差集
SELECT * 
  FROM product
 WHERE product_id NOT IN (SELECT product_id FROM product2)
UNION
SELECT * 
  FROM product2
 WHERE product_id NOT IN (SELECT product_id FROM product)

4.2 连结(JOIN)

4.2.1 内连结(INNER JOIN)

-- 内连结
FROM <tb_1> INNER JOIN <tb_2> ON <condition(s)>

4.2.1.1 使用内连结从两个表获取信息

关于内连结,需要注意以下三点:
要点一: 进行连结时需要在 FROM 子句中使用多张表.
要点二:必须使用 ON 子句来指定连结条件.
ON 子句是专门用来指定连结条件的, 我们在上述查询的 ON 之后指定两张表连结所使用的列以及比较条件, 基本上, 它能起到与 WHERE 相同的筛选作用。
要点三: SELECT 子句中的列最好按照 表名.列名 的格式来使用.

4.2.1.2 结合 WHERE 子句使用内连结

如果需要在使用内连结的时候同时使用 WHERE 子句对检索结果进行筛选, 则需要把 WHERE 子句写在 ON 子句的后边
查询的执行顺序:
FROM 子句->WHERE 子句->SELECT 子句
也就是说, 两张表是先按照连结列进行了连结, 得到了一张新表, 然后 WHERE 子句对这张新表的行按照两个条件进行了筛选, 最后, SELECT 子句选出了那些我们需要的列.
练习题:
找出每个商店里的衣服类商品的名称及价格等信息. 希望得到如下结果
在这里插入图片描述

-- 参考答案 1--不使用子查询
SELECT  SP.shop_id,SP.shop_name,SP.product_id 
       ,P.product_name, P.product_type, P.purchase_price
  FROM shopproduct  AS SP 
 INNER JOIN product AS P 
    ON SP.product_id = P.product_id
 WHERE P.product_type = '衣服';
-- 参考答案 2--使用子查询
SELECT  SP.shop_id, SP.shop_name, SP.product_id
      ,P.product_name, P.product_type, P.purchase_price
 FROM shopproduct AS SP 
INNER JOIN --从 product 表找出衣服类商品的信息
 (SELECT product_id, product_name, product_type, purchase_price
    FROM product	
   WHERE product_type = '衣服')AS P 
  ON SP.product_id = P.product_id;

4.2.1.3 结合GROUP BY 子句使用内连结

练习题:
每个商店中, 售价最高的商品的售价分别是多少?

SELECT SP.shop_id
      ,SP.shop_name
      ,MAX(P.sale_price) AS max_price
  FROM shopproduct AS SP
 INNER JOIN product AS P
    ON SP.product_id = P.product_id
 GROUP BY SP.shop_id,SP.shop_name

4.2.1.4 自连结(SELF JOIN)

需要注意, 自连结并不是区分于内连结和外连结的第三种连结, 自连结可以是外连结也可以是内连结, 它是不同于内连结外连结的另一个连结的分类方法.
找出每个商品种类当中售价高于该类商品的平均售价的商品.

-- 关联子查询
SELECT product_type, product_name, sale_price
  FROM product AS P1
 WHERE sale_price > (SELECT AVG(sale_price)
                       FROM product AS P2
                      WHERE P1.product_type = P2.product_type
                      GROUP BY product_type);

首先, 使用 GROUP BY 按商品类别分类计算每类商品的平均价格;接下来, 将上述查询与表 product 按照 product_type (商品种类)进行内连结.最后, 增加 WHERE 子句, 找出那些售价高于该类商品平均价格的商品。

-- 内连结
SELECT  P1.product_id
       ,P1.product_name
       ,P1.product_type
       ,P1.sale_price
       ,P2.avg_price
  FROM product AS P1
 INNER JOIN 
   (SELECT product_type,AVG(sale_price) AS avg_price 
      FROM product 
     GROUP BY product_type) AS P2 
    ON P1.product_type = P2.product_type
 WHERE P1.sale_price > P2.avg_price;

4.2.1.6 自然连结(NATURAL JOIN)

自然连结并不是区别于内连结和外连结的第三种连结, 它其实是内连结的一种特例–当两个表进行自然连结时, 会按照两个表中都包含的列名来进行等值内连结, 此时无需使用 ON 来指定连接条件.

SELECT *  FROM shopproduct NATURAL JOIN product

上述查询得到的结果, 会把两个表的公共列放在第一列(或者很多公共列), 然后按照两个表的顺序和表中列的顺序, 将两个表中的其他列都罗列出来。

4.2.2 外连结(OUTER JOIN)

左连结会保存左表中无法按照 ON 子句匹配到的行, 此时对应右表的行均为缺失值; 右连结则会保存右表中无法按照 ON 子句匹配到的行, 此时对应左表的行均为缺失值; 而全外连结则会同时保存两个表中无法按照 ON子句匹配到的行, 相应的另一张表中的行用缺失值填充.

-- 左连结     
FROM <tb_1> LEFT  OUTER JOIN <tb_2> ON <condition(s)>
-- 右连结     
FROM <tb_1> RIGHT OUTER JOIN <tb_2> ON <condition(s)>
-- 全外连结
FROM <tb_1> FULL  OUTER JOIN <tb_2> ON <condition(s)>

4.2.2.2 使用左连结从两个表获取信息

●外连结要点 1: 选取出单张表中全部的信息
●外连结要点 2:使用 LEFT、RIGHT 来指定主表.
一定要注意那些为null的值!!!

4.2.2.4 全外连结

MySQL 8.0目前还不支持全外连结,不过我们可以通过对左连结和右连结的结果进行UNION来实现全外连结。
也可以对多表进行连结
也可以实现非等值连结

4.2.5 交叉连结— CROSS JOIN(笛卡尔积)

交叉连结又叫笛卡尔积, 后者是一个数学术语. 两个集合做笛卡尔积, 就是使用集合 A 中的每一个元素与集合 B 中的每一个元素组成一个有序的组合。

-- 1.使用关键字 CROSS JOIN 显式地进行交叉连结
SELECT SP.shop_id
       ,SP.shop_name
       ,SP.product_id
       ,P.product_name
       ,P.sale_price
  FROM shopproduct AS SP
 CROSS JOIN product AS P;
--2.使用逗号分隔两个表,并省略 ON 子句
SELECT SP.shop_id
       ,SP.shop_name
       ,SP.product_id
       ,P.product_name
       ,P.sale_price
  FROM shopproduct AS SP , product AS P;

实际上, 正如书中所说, 上述写法中, 将 CROSS JOIN 改为逗号后, 正是内连结的旧式写法, 但在 ANSI 和 ISO 的 SQL-92 标准中, 已经将使用 INNER JION …ON… 的写法规定为标准写法, 因此极力推荐大家在平时写 SQL 查询时, 使用规范写法.
参考
http://datawhale.club/t/topic/473

猜你喜欢

转载自blog.csdn.net/zcy0108/article/details/111551442