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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章