【數據庫知識掃描】 | SQL複習-中篇 第11課 使用子查詢

意簡言賅,這一課介紹什麼是子查詢,如何使用它們。

早學完,早睡覺。困極了。

目錄

11.1 子查詢

11.2 利用子查詢進行過濾

11.3 作爲計算字段使用子查詢


11.1 子查詢

查詢(query)任何SQL語句都是查詢。但此術語一般指SELECT語句。

目前學習的所有SELECT語句都是簡單查詢,即從單個數據庫表中檢索數據的單條語句。

子查詢(subquery),即嵌套在其他查詢中的查詢。

講到子查詢,應該聊聊MySQL支持,對子查詢的支持是從4.1版本引入的(面試可能考!注意)。MySQL的早期版本不支持子查詢。

11.2 利用子查詢進行過濾

主要研究的對象是關係表,訂單存儲在兩個表中。每個訂單包含訂單編號、客戶ID、訂單日期,在Orders表中存儲爲一行。各訂單的物品存儲在相關的OrderItems表中。Orders表不存儲顧客信息,只存儲顧客ID。顧客的實際信息存儲在Customers表中。

假使麻煩來了,需要列出訂購物品RGAN01的所有顧客,怎麼搞呢?

  1. 檢索包含物品RGAN01的所有訂單的編號。
  2. 檢索具有前一步驟列出的訂單編號的所有顧客的ID。
  3. 檢索前一步驟返回的所有顧客ID的顧客信息。

起碼要分這散步吧,拿到訂單,拿到顧客,拿到顧客的信息纔算結束。那麼這三步檢索,能不能把某條SELECT語句返回的結果用於另一條SELECT語句的WHERE子句呢?

來試試,先說好,分別練習的語句不放上來,只放截圖,最後綜合句一起放:

SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01');

在SELECT語句中,子查詢總是從內向外處理。那麼考慮內部查詢,外部查詢的話,可以看左圖,上面的爲右圖的內部查詢,下面的爲外部查詢。輸出一樣,返回值相同。

另補一句:格式化SQL。說拿顏色區別開來,將子查詢分解成多行縮進,看的清晰明瞭。

現在得到了訂購物品RGAN01的所有顧客的ID。下一步是檢索這些顧客ID的顧客信息。也就是說,工作還沒幹完,但是是個好兆頭,接着做剩下的部分:

拿前面的語法也能做,得到結果,over~停!我們這一課學的子查詢,幹啥不把三個一起呢???

接着來。

SELECT cust_name,cust_contact FROM Customers 
WHERE cust_id IN(SELECT cust_id FROM Orders
WHERE order_num IN (SELECT order_num FROM OrderItems 
WHERE prod_id = 'RGAN01'));

終於挖出最後的結果,並且和上面得到結果一致。

在WHERE子句中使用子查詢能夠編寫出功能很強且很靈活的SQL語句。對於能嵌套的子查詢的數目沒有限制,不過在實際使用時由於性能的限制,不能嵌套太多的子查詢。

子查詢和性能這裏給出的代碼有效,並且獲得了所需的結果。但是,使用子查詢並不總是執行這類數據檢索的最有效方法。往後看就知道了,下一課就不太行。

11.3 作爲計算字段使用子查詢

使用子查詢的另一方法是創建計算字段。

比如說需要顯示Customers表中每個顧客的訂單總數。訂單與相應的顧客ID存儲在Orders表中。

那麼爲了拿到需要的結果,我們要:

(1)從Customers表中檢索顧客列表;

(2)對於檢索出的每個顧客,統計其在Orders表中的訂單數目。

統計數目好說,SELECT COUNT(*)對錶中的行進行計數,還可以通過提供一條WHERE子句來過濾某個特定的顧客ID,僅對該顧客的訂單進行計數。

 SELECT cust_name,cust_state, (SELECT COUNT(*) FROM Orders WHERE Orders.cust_id = Customers.cust_id) AS orders FROM Customers ORDER BY cust_name;

這條SELECT語句對Customers表中每個顧客返回三列:cust_name、cust_state和orders。orders是一個計算字段,它是由圓括號中的子查詢建立的。該子查詢對檢索出的每個顧客執行一次。在此例中,該子查詢執行了5次,因爲檢索出了5個顧客。

(哈欠連天的我也忙不上給這段分析加註釋了,直接copy上來了,主要是對於訂單中顧客計數,然後再去檢索出顧客信息)

用一個句點分隔表名和列名,在有可能混淆列名時必須使用這種語法。

子查詢中的WHERE子句與前面使用的WHERE子句稍有不同,因爲它使用了完全限定列名,而不只是列名(cust_id)。它指定表名和列名(Orders.cust_id和Customers.cust_id)。也就是在講,上面不是Orders.cust_id嗎?是避免跟Customers表中的搞混了。

然後書上爲了驗證這樣幹(沒有前面表名起作用的完全限定名)是不好滴,得不到想要的結果,做了一個小測試:

看看,多麼痛的領悟~拿到的數據完全不一樣,簡直崩潰!

雖然子查詢在構造這種SELECT語句時有用,但必須注意限制有歧義的列。不要搞二義性這種東西。

如果在SELECT語句中操作多個表,就應使用完全限定列名(帶個表名,做個人吧)來避免歧義。

不止一種解決方案,雖然爲了熟悉語法,我們強行將很多樣例代碼都運行出來了,但是這不代表,這些就是解決數據檢索的最優方法,後面學習,還會遇到更多問題更多組合解決方案,我們應當因地制宜,選擇合適的解決方案。

這節課就在我的哈欠和不停得得得~中度過去了。因爲筆記本電腦的鼠標“C”鍵一直自己按按按,家人又有需要,所以把筆記本和那個酷似網吧鍵盤的blingbling白鍵盤貢獻出去了,配合上次入手的白鼠標,一套好看極了。

可沒了鍵程舒適按壓力道剛好的鍵盤的我,打字都不香了。這並不是我今天不學三課的原因。

明天見,刻意練習,每日精進。晚安。

 

 

 

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