《SQL基礎教程》學習筆記Ch5

5復雜查詢

5-1視圖

視圖和表

當我們創建表時,會通過INSERT語句將數據保存到數據庫中,而數據庫中的數據會被保存到計算機的存儲設備中;但是使用視圖不會將數據保存在數據庫中,實際上視圖只保存SELECT語句,從視圖中讀取數據時,視圖會在內部執行該SELECT語句并創建出一張臨時表。

視圖的優點:
1.無需保存數據,節省存儲設備的容量
2.可以將頻繁使用的SELECT語句保存為視圖

創建視圖的方法
--創建ProductSum視圖
CREATE VIEW ProductSum (product_type, cnt_product) --視圖的列名
AS
SELECT product_type, COUNT(*)
  FROM Product
 GROUP BY product_type;
--使用視圖
SELECT product_type, cnt_product
  FROM ProductSum;
5-1.png

在FROM子句中使用視圖的查詢通常有兩個步驟:
1.首先執行定義視圖的SELECT子句;
2.根據得到的結果,再執行在FROM子句中使用視圖的SELECT子句

定義視圖時,可以使用WHERE,GROUP BY,HAVING等語句
此外應該避免下列的多重視圖(以視圖的基礎創建視圖):

CREATE VIEW ProductSumJim (product_type, cnt_product)
AS
SELECT product_type, cnt_product
  FROM ProductSum
 WHERE product_type = '辦公用品';
視圖的限制

1.定義視圖時不能使用ORDER BY子句
這是因為視圖和表一樣,數據行是沒有順序的
2.只在某些條件下可以進行更新
更新語句:INSERT,DELETE,UPDATE

比較有代表性的條件:
SELECT子句未使用DISTINCT;
FROM子句中只有一張表;
未使用GROUP BY子句;
未使用HAVING子句。

視圖和表需要同時進行更新,因而通過匯總(GROUP BY)得到的視圖無法進行更新。

--能夠進行更新的視圖
CREATE VIEW ProductJim (product_id, product_name, product_type, sale_price, purchase_price, regist_date)
AS
SELECT *
  FROM Product
 WHERE product_type = '辦公用品';
--向視圖中添加數據行
INSERT INTO ProductJim VALUES ('0009', '印章', '辦公用品', 95, 10, '2009-11-30');

另外,需要注意的是,在PostgreSQL運行上面的插入語句會報錯,由于PostgreSQL初始設定視圖為只讀,我們通過下列語句來允許PostgreSQL對視圖進行更新:

CREATE OR REPLACE RULE insert_rule
AS ON INSERT 
TO  ProductJim DO INSTEAD
INSERT INTO Product VALUES(
    new.product_id,
    new.product_name,
    new.product_type,
    new.sale_price,
    new.purchase_price,
    new.regist_date);

執行的結果:視圖及原表中數據均已被插入

刪除視圖
DROP VIEW ProductSum;

在PostgreSQL中此句會出錯,由于關聯視圖存在的原因,修改為:

DROP VIEW ProductSum CASCADE;

5-2子查詢

首先來復習一下前面是怎么使用視圖來查詢的:

--創建ProductSum視圖
CREATE VIEW ProductSum (product_type, cnt_product) --視圖的列名
AS
SELECT product_type, COUNT(*)
  FROM Product
 GROUP BY product_type;
--使用視圖
SELECT product_type, cnt_product
  FROM ProductSum;

所謂子查詢:

-- 在FROM子句中直接書寫定義視圖的SELECT語句
SELECT product_type, cnt_product
  FROM (SELECT product_type, COUNT(*) AS cnt_product
         FROM Product
         GROUP BY product_type) AS ProductSum;

這兩種方式得到的結果完全一致。
執行順序是先執行括號內的SELECT語句,再執行括號外的SELECT語句。

--嘗試增加子查詢的層數
SELECT product_type, cnt_product
  FROM ( SELECT *
       FROM ( SELECT product_type, COUNT(*) AS cnt_product
                    FROM Product
                   GROUP BY product_type) AS ProductSum
          WHERE cnt_product = 4) AS ProductSum2;
5-2.png
子查詢的名稱

原則上,子查詢必須使用AS設定名稱

標量子查詢

標量子查詢指的是必須且只能返回1行1列的子查詢
假設我們想要“查詢出銷售單價高于平均銷售單價的商品”

--錯誤的語句
--在WHERE子句中不能使用聚合函數
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > AVG(sale_price); --錯誤

要解決這個問題,我們可以使用標量子查詢語句

--計算平均銷售單價的標量子查詢
SELECT AVG(sale_price)
  FROM Product;
--選取出銷售單價高于全部商品的平均單價的商品
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > (SELECT AVG(sale_price)
                       FROM Product);
5-3.png
標量子查詢的書寫位置

能夠使用常數或者列名的地方,無論是SELECT子句、GROUP BY子句、HAVING子句還是ORDER BY子句,幾乎所有的地方都可以使用

--在SELECT子句中使用標量子查詢
SELECT product_id,
       product_name,
       sale_price,
        (SELECT AVG(sale_price)
               FROM Product)  AS avg_price
FROM Product;
--在HAVING子句中使用標量子查詢
SELECT product_type, AVG(sale_price)
  FROM Product
 GROUP BY product_type
HAVING AVG(sale_price) > (SELECT AVG(sale_price)
                            FROM Product);
使用標量子查詢時的注意事項

標量子查詢只能夠返回單一值,如果返回多行值,它就不再是標量子查詢,而僅僅是一個普通的子查詢

--由于不是標量子查詢,因此不能在SELECT子句中使用
SELECT product_id, 
       product_name,
       sale_price,
       (SELECT AVG(sale_price)
         FROM Product
         GROUP BY product_type) AS avg_price
  FROM Product;

該段會報錯,這是由于子查詢的結果是三個而不是一個,不再是標量子查詢,不可以寫在SELECT子句中

5-3關聯子查詢

普通的子查詢和關聯子查詢的區別

假設這次我們想要“查詢出某個商品類中高于此類商品平均銷售單價的商品”

--按照商品種類計算平均價格
SELECT AVG(sale_price)
  FROM Product
 GROUP BY product_type;
--發生錯誤的子查詢
SELECT product_id, product_name, sale_price
  FROM Product
 WHERE sale_price > (SELECT AVG(sale_price)
                       FROM Product
                    GROUP BY product_type);

這種方法顯然是錯誤的,因為普通的子查詢被當做了標量子查詢。
為了解決這個問題,可以利用關聯子查詢:

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);
5-4.png

在這里起到關鍵作用的是在子查詢中添加的WHERE子句的條件,它的意思是在同一商品種類中,對商品的銷售單價和平均單價進行比較。
由于作為比較對象的都是同一張Product表,因此要使用P1和P2兩個別名。
需要注意的是:
1.關聯子查詢也是用來對集合進行切分的
2.結合條件一定要寫在子查詢中

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 鼓浪嶼島上的手工茶餅坊里,我讓逗比幫我拍下這張照片,這是這次廈門之旅我最喜歡的一張照片。 逗比說,幫你拍了那么多張...
    影秋千閱讀 322評論 2 1
  • 不得不安利最近大火的電視劇《微微一笑很傾城》。 什么,你們都說楊洋在里面很高冷?不不不不,我不覺得高冷。這才是一個...
    晚來Yvonne閱讀 1,825評論 3 12
  • 一幅簡單的纏繞畫,纏繞的有點不規整 今天就當偷偷懶吧~ 超級簡單十分鐘搞定, 喜歡就動起手來了~
    小梅繪生活閱讀 603評論 4 5
  • 幸福幫第九期“如何提升孩子的學習興趣”微課堂語音整理。 本次微課老師將從以下幾點,為大家分享自己關于提升孩子的學習...
    幸福幫閱讀 331評論 0 0