(本文結合《SQL基礎教程》整理)
文章結構
- 視圖
- 子查詢
- 變量子查詢
- 關聯子查詢
- 如何用SQL解決業務問題
- 常見函數
視圖究竟是什麼呢?如果用一句話概述的話,就是“從 SQL 的角度來看視圖就是一張表”。資料庫中的資料實際上會被儲存到計算機的儲存設備(通常是硬碟)中。是以,我們通過 SELECT 語句查詢資料時,實際上就是從儲存設備(硬碟)中讀取資料,進行各種計算之後,再将結果傳回給使用者這樣一個過程。但是使用視圖時并不會将資料儲存到儲存設備之中,而且也不會将資料儲存到其他任何地方。實際上視圖儲存的是 SELECT 語句。我們從視圖中讀取資料時,視圖會在内部執行該 SELECT 語句并建立出一張臨時表,臨時表會在用戶端和資料庫斷開連接配接的時候自動删除。
(以上文字和圖檔整理自:《SQL基礎教程》)
視圖的優點:①由于視圖無需儲存資料,是以可以節省儲存設備的容量。
②第二個優點就是可以将頻繁使用的 SELECT 語句儲存成視圖,減少重複書寫。視圖建立好之後,隻需在 SELECT 語句中進行調用。在進行彙總以及複雜的查詢條件導緻 SELECT 語句非常龐大時,使用視圖可以大大提高效率。
③視圖中的資料會随着原表的變化自動更新,視圖就是封裝好的SELECT 語句,定義視圖時可以使用任何 SELECT 語句,既可以使用 WHERE、 GROUP BY、 HAVING,也可以通過 SELECT * 來指定全部列。
如何建立視圖:【也是在建立查詢中建立,然後重新整理即可】視圖的外在表現形式是一張臨時表
注意:SELECT 語句需要書寫在 AS 【像,和...一樣】關鍵字之後。 SELECT 語句中列的排列順序和視圖中列的排列順序相同。
如何使用視圖: 如何删除視圖: 注意事項:①在 FROM 子句中使用視圖的查詢,通常有如下兩個步驟:
通常來說,使用視圖的查詢通常需要執行 2 條以上的 SELECT 語句
②可以以視圖為基礎建立視圖的多重視圖,實際使用中,應該盡量避免在視圖的基礎上建立視圖。這是因為對多數 DBMS 來說,多重視圖會降低 SQL 的性能。
③定義視圖時不能使用ORDER BY子句。
④視圖和表需要同時進行更新,是以通過彙總得到的視圖無法進行更新(詳細原因見《SQL基礎教程》P156)。
子查詢
子查詢定義:子查詢就是将用來定義視圖的SELECT語句直接用于FROM子句當中,子查詢就是一次性視圖(SELECT語句)。是以與視圖不同,子查詢在SELECT語句執行完畢之後就會消失。
FROM子句之後的子查詢案例1:要求根據商品種類(product_type)對資料進行彙總。
先回憶一下視圖的建立和使用的過程:
表product
建立的視圖
再來看看能夠實作同樣功能的
子查詢的建立和使用的過程:
【非常重要:】from子句後,每個子查詢派生出來的表都需要有自己的别名,不然會報錯
案例2:找出商品總數量為3的商品品類名稱。
子查詢可以嵌套【但是不建議】:
我們嘗試解釋一下上述語句的含義:
①最内層的子查詢(ProductSum)與之前一樣,根據商品種類(product_type)對資料進行彙總。
②外層的子查詢将商品數量(cnt_product)限定為 3,結果就得到了 1 行廚房用具的資料,如下圖。
WHERE子句中的子查詢案例3:哪些學生的成績比課程0002的全部成績裡的任意一個高?【ANY (子查詢)括号裡的資料以集合形式呈現】
案例4:哪些學生的成績比課程0002的全部成績裡都高?【all(子查詢)】
需要注意的是:子查詢隻是充當了視圖的功能并不會産生新的視圖,就像視圖僅僅建立了一張臨時表是一個道理。
标量子查詢
标量子查詢的定義:标量就是單一的意思,标量子查詢就是
傳回單一值的子查詢。
案例:根據上表的資料結構考慮一個問題:查詢出銷售單價高于平均銷售單價的商品。
根據正常思維,幾乎會本能的在WHERE子句中使用聚集函數。
如下圖,我們發現SELECT 語句的查詢結果是單一的值(73266.6667)。是以,我們可以直接将這個結果用到之前失敗的查詢之中。
結合後的效果如下:
子查詢的結果是 73266.6667,是以會用該值替換子查詢的部分
需要注意的是:标量子查詢的書寫位置并不僅僅局限于 WHERE 子句中,
通常任何可以使用單一值的位置都可以使用【類似一個常數】。也就是說,
能夠使用常數或者列名的地方,無論是 SELECT 子句、GROUP BY 子句、 HAVING 子句,還是ORDER BY 子句,幾乎所有的地方都可以使用。
案例1:将全部商品的單價加入原表格
【我們将子查詢的語句放到了SELECT子句後】:
從上述結果可以看出,在商品一覽表中加入了全部商品的平均單價。有時我們會需要這樣的資料。
案例2:選取出銷售均價高于全部商品的平均銷售單價的商品種類
【我們将子查詢的語句放到了HAVING子句後】。
标量子查詢注意事項:①标量子查詢絕對不能傳回多行結果。也就是說,如果子查詢傳回了多行結果,那麼它就不再是标量子查詢,而僅僅是一個普通的子查詢了。
關聯子查詢
1.關聯子查詢:關聯子查詢會在涉及分組後的組内再計算的場景。 2.問題引入:
案例1:選取出各商品種類中高于該商品種類的平均銷售單價的商品。
'商品種類的平均銷售單價需要分組後再計算,需要用到關聯子查詢'問題拆解:①找出每個商品種類的平均銷售單價。②将各自商品與自己對應的商品種類的平均銷售單價進行比較。
第一步:找出每個商品種類的平均銷售單價。
第二步:将各自商品與自己對應的商品種類的平均銷售單價進行比較。
如果我們使用前一節(标量子查詢)的方法,直接把上述SELECT 語句使用到 WHERE 子句當中的話,就會發生錯誤。出錯原因前一節已經講過了,該子查詢會傳回 3 行結果(1000、300、146000),并不是标量子查詢。
正确的做法是使用關聯子查詢:
其中紅色方框的運作邏輯是:
①執行到紅框部分時,先從父查詢的P1表中取出第一行值,并且傳遞到子查詢中,然後第一行記錄中取出product_type值'衣服'【p1.product_type】,于是紅框等式右邊的值替換為:'衣服',于是
子查詢語句實際變成如下所示,并且将該次完整的子查詢結果傳回給外層的父查詢。
②将avg(sale_price)=1000作為傳回值,同時限定條件:product_type='衣服'【展現關聯】,傳回到父查詢中去,父查詢實際上成為:
③執行該次父查詢,我們發現,因為衣服隻有一個品類,商品種類的均值就是本身,是以查詢不到符合條件(大于1000且類型為衣服)。
④我們按上面相同的步驟,再從父查詢的P1表中取出第二行記錄傳入子查詢,得到第二行記錄中product_type的值為'辦公用品'【p1.product_type】,再重複上述幾步,我們發現'辦公用品'中的打孔器是符合篩選條件的,拆分的步驟大概如下。
⑤最後,循環以上步驟,将外部p1的每一行都傳遞到子查詢,子查詢依次讀取外部查詢傳遞來的每一行值,并将其用到子查詢上,直到外部查詢所有的行都處理完為止.然後傳回查詢最終查詢結果:
案例2:查詢每個商品的價格和它們
所處種類的平均價格。
'所處種類的平均價格需要分組後在計算,需要關聯子查詢'該關聯子查詢中,Group By對product_type進行分組其實沒有必要,因為上面where子句完成了實際上的分組功能
總結:①關聯子查詢主要使用場景為:
分組後需要進行組内操作的場景,組内的操作會由關聯子查詢完成,同組的類似工作,靠父查詢協調,遇到關聯子查詢的問題時,需要清晰明白各層查詢的具體功能。②關聯子查詢的執行原理:關聯子查詢會引用外部查詢中的
一列或多列.在執行時,外部查詢的
每一行都被一次一行地傳遞給子查詢.子查詢依次讀取外部查詢傳遞來的每一行值,子查詢為每一行資料執行一次并傳回它的記錄,直到父查詢所有的行都處理完為止,然後傳回查詢結果。
關聯子查詢和普通子查詢的差別:①關聯子查詢的執行依賴于外部查詢的資料,外部查詢執行一行,子查詢就執行一次。此外,在關聯子查詢中是資訊流是雙向的。外部查詢的每行資料傳遞一個值給子查詢,
然後子查詢為每一行資料執行一次并傳回它的記錄。然後,外部查詢根據傳回的記錄做出決策。
②非相關子查詢是獨立于外部查詢的子查詢,非相關子查詢是獨立于外部查詢的子查詢,子查詢總共執行一次,執行完畢後将值傳遞給外部查詢。
③關聯子查詢中: 1. 先執行外層查 2. 再執行内層查詢
④普通子查詢中: 1. 先執行内層查詢 2. 再執行外層查詢
如何用SQL解決業務問題
①翻譯成大白話
②寫出分析思路
③寫出對應的SQL子句
各種函數
日期函數:
Sqlzoo練習:
不知道為什麼出錯......
gdp>0,是為了排除NULL值,NULL不能使用比較運算符,因為NULL表示不确定,無法确定排序
那為什麼上面MAX()函數沒有出現問題呢?因為當列名作為參數傳入聚集函數的時候,那麼在計算之前就已經把NULL 排除在外了。是以,無論有多少個 NULL 都會被無視。但是如果是COUNT(*)這樣的形式,NULL會納入運算。
嘗試解析一下整個運作流程,加深對關聯子查詢的了解和記憶。
注意的ALL的靈活使用,若此處改成>=ALL,則可以選出每個州,排名最後的那個國家。
上圖中group by continent包不包含都無所謂
第十題中,子查詢引用了外部查詢的兩列【continent】【name】。