SQL 基礎知識梳理(五) - 復雜查詢
目錄
- 視圖
- 子查詢
- 關聯子查詢
一、視圖
1.視圖和表
(1)視圖:從 SQL 的角度來看視圖就是一張表。
(2)視圖和表的區別:是否保存了實際的數據。數據庫中的數據實際上保存到計算機的存儲設備(如硬盤);視圖實際上保存的是 SELECT 語句,從視圖中讀取數據時,視圖會在內部執行該 SELETC 語句並創建出一張臨時表。
(3)視圖的優點:
①無需保存數據,節省存儲設備的容量。
②保存頻繁使用的 SELECT 語句,提高效率。
【總結】表中存儲的是實際數據,視圖保存的是 SELECT 語句。
【總結】應該將經常使用的 SELECT 語句做成視圖。
2.創建視圖
--語法 --CREATE VIEW 視圖名稱(<視圖列名1>, <視圖列名2>, ...) --AS --<SELECT 語句>
--示例:創建視圖 CREATE VIEW ShohinSum(shohin_bunrui, cnt_shohin) AS SELECT shohin_bunrui, COUNT(*) FROM dbo.Shohin GROUP BY shohin_bunrui;
--示例:使用視圖 SELECT * FROM shohinSum;
視圖就是保存好的 SELECT 語句。我們將頻繁的查詢操作保存成視圖,就可以提高效率了。
(1)使用視圖的查詢
在FROM 子句中使用視圖的查詢,通常有如下步驟:
①執行定義視圖的 SELECT 語句;
②根據得到的結果,再執行在 FROM 子句中使用視圖的 SELECT 子句。
也就意味着可能會出現“多重視圖”,我們應盡量避免在視圖的基礎上創建視圖,因為這樣很可能會降低 SQL 的性能。
【備注】應避免在視圖的基礎上創建視圖。
(2)視圖的限制 - 創建視圖時不能使用 ORDER BY 子句(但可以使用其它 SELECT 子句)
圖:假設這是一個新創建的視圖
(3)視圖的限制 - 更新視圖
圖:假設上圖去掉 ORDER BY 子句,在成功創建 ShohinSm 視圖后,再執行插入時仍然報錯
【備注】通過聚合得到的視圖不能進行更新。
下面是一個成功創建視圖並可以執行插入語句的示例。
創建視圖並插入
檢測數據
雖然可以對視圖實現更新操作,但我們通常不這樣做。
3.刪除視圖
--語法 --DROP VIEW 視圖名稱(<視圖列名1>, <視圖列名2>, ...)
--示例 DROP VIEW shohinSum
二、子查詢
1.子查詢和視圖:
(1)子查詢:將用來定義視圖的 SELECT 語句直接用於 FROM 子句當中。
--示例 SELECT shohin_bunrui, cnt_shohin FROM ( SELECT shohin_bunrui, COUNT(*) AS cnt_shohin FROM Shohin GROUP BY shohin_bunrui ) AS ShohinSum; --記得加上別名哦
圖中的 AS ShohinSum 是子查詢的名稱,子查詢(subquery)就是“次級(sub)”的“查詢(query)”。先執行①的內層查詢,再執行②的外層查詢。
【備注】子查詢作為內層查詢會首先執行。
子查詢的層數沒有限制,出於性能和可讀性考慮,應避免使用多層嵌套的子查詢。
2.標量子查詢
上面的子查詢基本上都會返回多行結果(雖然偶爾只返回 1 行數據),而標量子查詢,就是必須而且只能返回 1 行 1 列的結果。
【備注】標量子查詢就是返回單一值的子查詢。
--示例:查詢出銷售單價高於平均銷售單價的商品,hanbai_tanka:銷售單價 SELECT * FROM dbo.Shohin WHERE hanbai_tanka > ( SELECT AVG(hanbai_tanka) FROM dbo.Shohin )
3.在其它地方書寫標量子查詢
能夠使用常數或者列名的地方很多:SELECT 子句、GROUP BY 子句、HAVING 子句,或 ORDER BY 子句等。
--示例:在 SELECT 子句中使用標量子查詢 SELECT shohin_id , shohin_mei , hanbai_tanka , ( SELECT AVG(hanbai_tanka) FROM dbo.Shohin ) AS avg_hanbai_tanka FROM dbo.Shohin
--示例:在 HAVING 子句中使用標量子查詢 SELECT shohin_bunrui, AVG(hanbai_tanka) FROM dbo.Shohin GROUP BY shohin_bunrui HAVING AVG(hanbai_tanka) > ( SELECT AVG(hanbai_tanka) FROM dbo.Shohin )
【注意】使用標量子查詢時,該子查詢不能返回多行結果。
三、關聯子查詢
為了直觀顯示字段名,現在將所有列名都改成中文。

CREATE TABLE Shohin ( 商品編號 CHAR(4) NOT NULL, 商品名稱 VARCHAR(100) NOT NULL, 商品分類 VARCHAR(32) NOT NULL, 銷售單價 INTEGER , 進貨單價 INTEGER , 登記日期 DATE , PRIMARY KEY (商品編號) ); INSERT INTO Shohin VALUES ('0001', 'T恤' ,'衣服', 1000, 500, '2009-09-20'); INSERT INTO Shohin VALUES ('0002', '打孔器', '辦公用品', 500, 320, '2009-09-11'); INSERT INTO Shohin VALUES ('0003', '運動T恤', '衣服', 4000, 2800, NULL); INSERT INTO Shohin VALUES ('0004', '菜刀', '廚房用具', 3000, 2800, '2009-09-20'); INSERT INTO Shohin VALUES ('0005', '高壓鍋', '廚房用具', 6800, 5000, '2009-01-15'); INSERT INTO Shohin VALUES ('0006', '叉子', '廚房用具', 500, NULL, '2009-09-20'); INSERT INTO Shohin VALUES ('0007', '擦菜板', '廚房用具', 880, 790, '2008-04-28'); INSERT INTO Shohin VALUES ('0008', '圓珠筆', '辦公用品', 100, NULL, '2009-11-11');
1.普通子查詢和關聯子查詢的區別
思考:選取出各商品分類中高於該分類平均銷售單價的商品?
圖
圖 因為內部的子查詢不是前一節中的標量子查詢(這里返回三行結果),所以報錯
【備注】在 WHERE 子句中使用子查詢時,該子查詢的結果必須為單一值。
--正確的語句:采用關聯子查詢 SELECT * FROM dbo.Shohin s1 WHERE 銷售單價 > ( SELECT AVG(s2.銷售單價) AS avg_銷售單價 FROM dbo.Shohin s2 WHERE s1.商品分類 = s2.商品分類 GROUP BY s2.商品分類 )
圖
關鍵作用的語句:在子查詢中添加的 WHERE 子句的條件。該條件的意思是:在同種商品中對個商品的銷售單價和平均銷售單價作比較。
2.結合條件一定要寫在子查詢
圖:把關聯條件移到子查詢之外
這里涉及到關聯名稱的作用域。子查詢內部設定的關聯名稱,只能在該子查詢內部使用。也可以這樣說:“內部可以看到外部,而外部看不到內部”。
備注
這里采用 MS SQL Server 進行驗證,不保證所有的 DBMS 執行結果正確。
《SQL 基礎知識梳理》系列
《SQL 基礎知識梳理(六)- 函數、謂詞、CASE 表達式》
【博主】反骨仔
【原文】http://www.cnblogs.com/liqingwen/p/5939796.html
【參考】《SQL ゼロからはじめるデータベース操作》