圖解 SQL 執(zhí)行順序,通俗易懂!
這是一條標準的查詢語句:
這是我們實際上SQL執(zhí)行順序:
●我們先執(zhí)行from,join來確定表之間的連接關(guān)系,得到初步的數(shù)據(jù)
●where對數(shù)據(jù)進行普通的初步的篩選
●group by 分組
●各組分別執(zhí)行having中的普通篩選或者聚合函數(shù)篩選。
●然后把再根據(jù)我們要的數(shù)據(jù)進行select,可以是普通字段查詢也可以是獲取聚合函數(shù)的查詢結(jié)果,如果是集合函數(shù),select的查詢結(jié)果會新增一條字段
●將查詢結(jié)果去重distinct
●最后合并各組的查詢結(jié)果,按照order by的條件進行排序
我們在理解SELECT語法的時候,還需要了解SELECT執(zhí)行時的底層原理。只有這樣,才能讓我們對SQL有更深刻的認識。
其中你需要記住SELECT查詢時的兩個順序:
1.關(guān)鍵字的順序是不能顛倒的:
2.SELECT語句的執(zhí)行順序(在MySQL和Oracle中,SELECT執(zhí)行順序基本相同):
比如你寫了一個SQL語句,那么它的關(guān)鍵字順序和執(zhí)行順序是下面這樣的:
在SELECT語句執(zhí)行這些步驟的時候,每個步驟都會產(chǎn)生一個虛擬表,然后將這個虛擬表傳入下一個步驟中作為輸入。需要注意的是,這些步驟隱含在SQL的執(zhí)行過程中,對于我們來說是不可見的。
數(shù)據(jù)的關(guān)聯(lián)過程
數(shù)據(jù)庫中的兩張表
from&join&where
用于確定我們要查詢的表的范圍,涉及哪些表。
選擇一張表,然后用join連接
選擇多張表,用where做關(guān)聯(lián)條件
我們會得到滿足關(guān)聯(lián)條件的兩張表的數(shù)據(jù),不加關(guān)聯(lián)條件會出現(xiàn)笛卡爾積。
group by
按照我們的分組條件,將數(shù)據(jù)進行分組,但是不會篩選數(shù)據(jù)。
比如我們按照即id的奇偶分組
having&where
having中可以是普通條件的篩選,也能是聚合函數(shù)。而where只能是普通函數(shù),一般情況下,有having可以不寫where,把where的篩選放在having里,SQL語句看上去更絲滑。
使用where再group by
先把不滿足where條件的數(shù)據(jù)刪除,再去分組
使用group by再having
先分組再刪除不滿足having條件的數(shù)據(jù),這兩種方法有區(qū)別嗎,幾乎沒有!
舉個例子:
100/2=50,此時我們把100拆分(10+10+10+10+10…)/2=5+5+5+…+5=50,只要篩選條件沒變,即便是分組了也得滿足篩選條件,所以where后group by 和group by再having是不影響結(jié)果的!
不同的是,having語法支持聚合函數(shù),其實having的意思就是針對每組的條件進行篩選。我們之前看到了普通的篩選條件是不影響的,但是having還支持聚合函數(shù),這是where無法實現(xiàn)的。
當前數(shù)據(jù)分組情況
執(zhí)行having的篩選條件,可以使用聚合函數(shù)。篩選掉工資小于各組平均工資的having salary
select
分組結(jié)束之后,我們再執(zhí)行select語句,因為聚合函數(shù)是依賴于分組的,聚合函數(shù)會單獨新增一個查詢出來的字段,這里用紫色表示,這里我們兩個id重復了,我們就保留一個id,重復字段名需要指向來自哪張表,否則會出現(xiàn)唯一性問題。最后按照用戶名去重。
將各組having之后的數(shù)據(jù)再合并數(shù)據(jù)。
order by
最后我們執(zhí)行order by 將數(shù)據(jù)按照一定順序排序,比如這里按照id排序。如果此時有l(wèi)imit那么查詢到相應的我們需要的記錄數(shù)時,就不繼續(xù)往下查了。
limit
記住limit是最后查詢的,為什么呢?假如我們要查詢年級最小的三個數(shù)據(jù),如果在排序之前就截取到3個數(shù)據(jù)。實際上查詢出來的不是最小的三個數(shù)據(jù)而是前三個數(shù)據(jù)了,記住這一點。
我們?nèi)绻鹟imit 0,3竊取前三個數(shù)據(jù)再排序,實際上最少工資的是2000,3000,4000。你這里只能是4000,5000,8000了。