iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
1
AI & Data

與資料庫共舞系列 第 6

Day 6 — SQL Subquery 子查詢與布林運算

昨天我們介紹比較複雜查詢,仍然是單層的查詢。什麼意思? 就是整個查詢中只出現一次的 Select — From — Where。有時候遇到較為複雜的查詢時,我們就得利用多層。今天我們來看看這樣的查詢要怎麼寫。要特別在這裡先說明,為了讓讀者比較容易理解這些多層的查詢運作原理和模式,下面的範例和解釋,很多都可以用單層查詢就完成。

今天要介紹的這個叫做子查詢(Subquery),也就是在指令中,我們先用一個指令找出我們要的資料,並在使用另一個查詢中使用這些取得的資料。

選取中使用子查詢

我們繼續沿用上個禮拜所匯入的資料,首先我們第一個查詢想要找的是編號C001的客戶,他所寫下針對價格超過30塊商品的回饋。查詢的寫法就可以像下面這樣:

Select * 
From (
		Select * 
		From menu 
		Where price > 30) as subtable 
		natural join 
		review 
where customerID = 'C001';

https://ithelp.ithome.com.tw/upload/images/20200906/20129829MUio7Zn7ZT.png

那我們現在來解構這一個查詢裡面說使用到的指令,跟昨天我們說的一樣在SQL的指令當中都是先從 From 這一個區段開始執行。所以我們先看中間這段:

Select * 
From menu 
Where price > 30;

這段指令應該蠻容易理解的吧,沒有錯這段指令回傳的將會是菜單關係表中,價格超過30元的資料列。這時候我們將它重新命名叫做 subtable 並且將它與評分關係表做 natural join

https://ithelp.ithome.com.tw/upload/images/20200906/20129829MjBbxCjka0.png

當兩個表格連結完成之後最後我們在透過 where customerID = 'C001' 來過濾掉並選取由客戶 C001 所撰寫的評分。

條件中的子查詢

可想而知的事情是既然我們可以從選擇表格的地方進行子查詢,那我們在給條件的程式區塊 (Where) 當中,同樣也可以使用子查詢來幫助我們過濾並選取所需要的資料。讓我們看下面這個例子:

Select * 
From review 
where MenuID = (
		Select MenuID 
		From menu 
    Where price = 80);

https://ithelp.ithome.com.tw/upload/images/20200906/201298293vttujvgyJ.png

在這個例子中,我們想查詢的是售價等於80元商品的會員回饋。在這裡要特別注意的事情是除非子查詢回傳的是單一個結果,就像上面這一個範例一樣運氣很好的是在菜單中只有一個品項價格是80元,否則就會像下面這個查詢一樣出現錯誤。

https://ithelp.ithome.com.tw/upload/images/20200906/20129829kK2Y3FvIVw.png

這這個有錯誤的查詢當中我們查找的是選出價格超過20塊的商品回饋,但是因為超過20塊的商品有超過1個,所以SQL就告訴我們子查詢回傳了超過一行他沒有辦法檢查兩者的 MenuID 是否相同。所以這時候我們就會開始應用布林運算( Boolean Operations)。

子查詢與布林運算

既然有時候我們會想要比對一個資料的屬性有沒有出現在一組資料之中,這時候SQL提供了我們像 IN這樣子的指令。顧名思義就是查詢,在回饋裡面的 MenuID 有沒有出現在我們子查詢的一組MenuID之中。這裡有沒有注意到,子查詢的選取區段,只列出了 MenuID。這就是因為 IN 這一個指令對應的就只是一個列表。有興趣的讀者可以試著把這些子查詢拆解單獨運行。

Select * 
From review 
where MenuID IN (Select MenuID from menu where price > 20);

https://ithelp.ithome.com.tw/upload/images/20200906/20129829jIPUacWDfm.png

這種布林運算其實還有蠻多的,在這邊我們最後講解一個比較複雜的布林運算關鍵字: ExistsExists這個關鍵字就是在判斷某個資料植有沒有出現在子查詢中,所以同樣的我們可以把上面的查詢改寫成

Select * 
From review 
where Exists (
			Select * 
			From menu 
			Where menu.menuID = review.MenuID And price > 20
);

改寫過後會發現,我們在子查詢中,會先檢查子查詢的 Menu 關係表中的 MenuID 與 Review 關係表中的 ReviewID 是否相同。在相同的情況之下再比對價格是否大於20元,最後再核對 Review 每一列資料是否出現再這個子查詢中,並印出有出現過的資料。

今天解釋的東西有一點點複雜,但其實在理解SQL的過程當中,抓住執行順序和子查詢的中間值,是可以協助理解。之所以選擇使用資料關係表相對簡單資料量小的原因也是如此,今天和前幾天所寫的SQL語言都可以用紙筆推導出一樣的結果。明天我們要來解釋SQL中的集合!


上一篇
Day 5 — 用 SQL 串起不同表格
下一篇
Day 7 — MySQL 中的集合運算
系列文
與資料庫共舞30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言