意簡言賅,這一課介紹什麼是子查詢,如何使用它們。
早學完,早睡覺。困極了。
目錄
11.1 子查詢
查詢(query)任何SQL語句都是查詢。但此術語一般指SELECT語句。
目前學習的所有SELECT語句都是簡單查詢,即從單個數據庫表中檢索數據的單條語句。
子查詢(subquery),即嵌套在其他查詢中的查詢。
講到子查詢,應該聊聊MySQL支持,對子查詢的支持是從4.1版本引入的(面試可能考!注意)。MySQL的早期版本不支持子查詢。
11.2 利用子查詢進行過濾
主要研究的對象是關係表,訂單存儲在兩個表中。每個訂單包含訂單編號、客戶ID、訂單日期,在Orders表中存儲爲一行。各訂單的物品存儲在相關的OrderItems表中。Orders表不存儲顧客信息,只存儲顧客ID。顧客的實際信息存儲在Customers表中。
假使麻煩來了,需要列出訂購物品RGAN01的所有顧客,怎麼搞呢?
- 檢索包含物品RGAN01的所有訂單的編號。
- 檢索具有前一步驟列出的訂單編號的所有顧客的ID。
- 檢索前一步驟返回的所有顧客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白鍵盤貢獻出去了,配合上次入手的白鼠標,一套好看極了。
可沒了鍵程舒適按壓力道剛好的鍵盤的我,打字都不香了。這並不是我今天不學三課的原因。
明天見,刻意練習,每日精進。晚安。