結合上圖标沪,整理出如下偽SQL查詢語句
從這個順序中我們可以發(fā)現(xiàn),所有的查詢語句都是從?FROM?開始執(zhí)行的军浆。在實際執(zhí)行過程中,每個步驟都會為下一個步驟生成一個虛擬表申钩,這個虛擬表將作為下一個執(zhí)行步驟的輸入罗洗。 接下來,我們詳細的介紹下每個步驟的具體執(zhí)行過程馏鹤。
1 FROM?執(zhí)行笛卡爾積
FROM 才是 SQL 語句執(zhí)行的第一步勃救,并非 SELECT 瓢省。對FROM子句中的前兩個表執(zhí)行笛卡爾積(交叉聯(lián)接)废亭,生成虛擬表VT1,獲取不同數(shù)據(jù)源的數(shù)據(jù)集粗恢。
FROM子句執(zhí)行順序為從后往前佛掖、從右到左拴魄,F(xiàn)ROM 子句中寫在最后的表(基礎表 driving table)將被最先處理,即最后的表為驅動表跛溉,當FROM 子句中包含多個表的情況下,我們需要選擇數(shù)據(jù)最少的表作為基礎表。
2 ON 應用ON過濾器
對虛擬表VT1?應用ON篩選器落萎,ON 中的邏輯表達式將應用到虛擬表?VT1中的各個行瓷产,篩選出滿足ON 邏輯表達式的行,生成虛擬表?VT2?。
3 JOIN 添加外部行
如果指定了OUTER JOIN保留表中未找到匹配的行將作為外部行添加到虛擬表?VT2炎疆,生成虛擬表?VT3形入。保留表如下:
LEFT OUTER JOIN把左表記為保留表
RIGHT OUTER JOIN把右表記為保留表
FULL OUTER JOIN把左右表都作為保留表
在虛擬表?VT2表的基礎上添加保留表中被過濾條件過濾掉的數(shù)據(jù)全跨,非保留表中的數(shù)據(jù)被賦予NULL值,最后生成虛擬表?VT3亿遂。
如果FROM子句包含兩個以上的表,則對上一個聯(lián)接生成的結果表和下一個表重復執(zhí)行步驟1~3蛇数,直到處理完所有的表為止挪钓。
4 WHERE 應用WEHRE過濾器
對虛擬表?VT3應用WHERE篩選器。根據(jù)指定的條件對數(shù)據(jù)進行篩選苞慢,并把滿足的數(shù)據(jù)插入虛擬表?VT4诵原。
由于數(shù)據(jù)還沒有分組,因此現(xiàn)在還不能在WHERE過濾器中使用聚合函數(shù)對分組統(tǒng)計的過濾挽放。
同時绍赛,由于還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的辑畦。
備注:
?應用where篩選器吗蚌,對上一步生產(chǎn)的虛擬表引用where篩選器,生成虛擬表vt4纯出,在這有個比較重要的細節(jié)不得不說一下蚯妇,對于包含outer join子句的查詢敷燎,就有一個讓人感到困惑的問題,到底在on篩選器還是用where篩選器指定邏輯表達式呢箩言?on和where的最大區(qū)別在于硬贯,如果在on應用邏輯表達式那么在第三步outer join中還可以把移除的行再次添加回來,而where的移除的最終的陨收。舉個簡單的例子饭豹,有一個學生表(班級,姓名)和一個成績表(姓名,成績),我現(xiàn)在需要返回一個x班級的全體同學的成績务漩,但是這個班級有幾個學生缺考拄衰,也就是說在成績表中沒有記錄。為了得到我們預期的結果我們就需要在on子句指定學生和成績表的關系(學生.姓名=成績.姓名)那么我們是否發(fā)現(xiàn)在執(zhí)行第二步的時候饵骨,對于沒有參加考試的學生記錄就不會出現(xiàn)在vt2中翘悉,因為他們被on的邏輯表達式過濾掉了,但是我們用left outer join就可以把左表(學生)中沒有參加考試的學生找回來,因為我們想返回的是x班級的所有學生居触,如果在on中應用學生.班級='x'的話诗越,left outer join會把x班級的所有學生記錄找回砖瞧,所以只能在where篩選器中應用學生.班級='x' 因為它的過濾是最終的。
5 GROUP BY 分組
按GROUP BY子句中的列/列表將虛擬表?VT4中的行唯一的值組合成為一組嚷狞,生成虛擬表VT5。如果應用了GROUP BY床未,那么后面的所有步驟都只能得到的虛擬表VT5的列或者是聚合函數(shù)(count竭翠、sum、avg等)薇搁。原因在于最終的結果集中只為每個組包含一行斋扰。
同時,從這一步開始啃洋,后面的語句中都可以使用SELECT中的別名传货。
6?AGG_FUNC?計算聚合函數(shù)
計算 max 等聚合函數(shù)。SQL Aggregate 函數(shù)計算從列中取得的值宏娄,返回一個單一的值问裕。常用的 Aggregate 函數(shù)包涵以下幾種:
AVG:返回平均值
COUNT:返回行數(shù)
FIRST:返回第一個記錄的值
LAST:返回最后一個記錄的值
MAX: 返回最大值
MIN:返回最小值
SUM: 返回總和
7 WITH 應用ROLLUP或CUBE
對虛擬表?VT5應用ROLLUP或CUBE選項,生成虛擬表?VT6孵坚。
CUBE 和 ROLLUP 區(qū)別如下:
CUBE 生成的結果數(shù)據(jù)集顯示了所選列中值的所有組合的聚合粮宛。
ROLLUP 生成的結果數(shù)據(jù)集顯示了所選列中值的某一層次結構的聚合窥淆。
8 HAVING 應用HAVING過濾器
對虛擬表VT6應用HAVING篩選器。根據(jù)指定的條件對數(shù)據(jù)進行篩選巍杈,并把滿足的數(shù)據(jù)插入虛擬表VT7忧饭。
HAVING?語句在SQL中的主要作用與WHERE語句作用是相同的,但是HAVING是過濾聚合值筷畦,在 SQL 中增加 HAVING 子句原因就是眷昆,WHERE 關鍵字無法與聚合函數(shù)一起使用,HAVING子句主要和GROUP BY子句配合使用汁咏。
9 SELECT 選出指定列
將虛擬表?VT7中的在SELECT中出現(xiàn)的列篩選出來亚斋,并對字段進行處理,計算SELECT子句中的表達式攘滩,產(chǎn)生虛擬表?VT8帅刊。
10 DISTINCT 行去重
將重復的行從虛擬表?VT8中移除,產(chǎn)生虛擬表?VT9漂问。DISTINCT用來刪除重復行赖瞒,只保留唯一的。
事實上如果應用了group by子句那么distinct是多余的蚤假,原因同樣在于栏饮,分組的時候是將列中唯一的值分成一組,同時只為每一組返回一行記錄磷仰,那么所有的記錄都將是不相同的袍嬉。
11 ORDER BY 排列
將虛擬表?VT9中的行按ORDER BY 子句中的列/列表排序,生成游標?VC10?灶平;此時返回的一個游標伺通,而不是虛擬表。sql是基于集合的理論的逢享,集合不會預先對他的行排序罐监,它只是成員的邏輯集合,成員的順序是無關緊要的瞒爬。對表進行排序的查詢可以返回一個對象弓柱,這個對象包含特定的物理順序的邏輯組織。這個對象就叫游標侧但。正因為返回值是游標矢空,那么使用order by 子句查詢不能應用于表表達式。排序是很需要成本的俊犯,除非你必須要排序妇多,否則最好不要指定order by,最后燕侠,在這一步中是第一個也是唯一一個可以使用select列表中別名的步驟者祖。
12 LIMIT/OFFSET 指定返回行
從VC10的開始處選擇指定數(shù)量行立莉,生成虛擬表?VT11,并返回調用者七问。
實例
接下來蜓耻,我們看一個實例,以下SQL查詢語句是否存在問題械巡?
首先刹淌,我們先看下如上SQL的執(zhí)行順序,如下:
首先執(zhí)行 FROM 子句, 從學生成績表中組裝數(shù)據(jù)源的數(shù)據(jù)讥耗。
執(zhí)行 WHERE 子句, 篩選學生成績表中所有學生的數(shù)學成績不為 NULL 的數(shù)據(jù) 有勾。
執(zhí)行 GROUP BY 子句, 把學生成績表按 "班級" 字段進行分組。
計算 avg 聚合函數(shù), 按找每個班級分組求出?數(shù)學平均成績古程。
執(zhí)行 HAVING 子句, 篩選出班級?數(shù)學平均成績大于 75 分的蔼卡。
執(zhí)行SELECT語句,返回數(shù)據(jù)挣磨,但別著急雇逞,還需要執(zhí)行后面幾個步驟。
執(zhí)行 ORDER BY 子句, 把最后的結果按 "數(shù)學平均成績" 進行排序茁裙。
執(zhí)行LIMIT 塘砸,限制僅返回3條數(shù)據(jù)。結合ORDER BY 子句晤锥,即返回所有班級中數(shù)學平均成績的前三的班級及其數(shù)學平均成績掉蔬。
思考一下,如果我們將上面語句改成查近,如下會怎樣眉踱?
我們發(fā)現(xiàn)阳懂,若將?avg(數(shù)學成績) > 75?放到WHERE子句中豺谈,此時GROUP BY語句還未執(zhí)行眨猎,因此此時聚合值?avg(數(shù)學成績)?還是未知的,因此會報錯戈泼。