SQL語言不同于其他編程語言(如C++,Java)丘侠,最明顯的不同體現(xiàn)在處理代碼的順序上。在大多數(shù)編程語言中逐样,代碼按編碼順序被處理蜗字。但在SQL語言中打肝,第一個被處理的子句總數(shù)FROM子句,下面顯示了邏輯查詢處理的順序以及步驟的序號
(8)SELECT (9)DISTINCT <select_list>
(1)FROM <left_table>
(3)<join_type> JOIN <right_table>
(2)ON <join_condition>
(4)WHERE <where_condition>
(5)GROUP BY <group_by_list>
(6)WITH {CUBE|ROLLUP}
(7)HAVING <having_condition>
(10)ORDER BY <order_by_list>
(11)LIMIT <limit_number>
我們來具體分析查詢處理的各個階段
- FROM:對FROM子句中的左表<left_table>和右表<right_table>執(zhí)行笛卡爾積挪捕,產(chǎn)生虛擬表VT1
- ON:對虛擬表VT1應(yīng)用ON篩選粗梭,只有那些符合<join_condition>的行才被插入虛擬表VT2中
- JOIN:如果指定了OUTER JOIN(如LEFT OUTER JOIN ,RIGTH OUTER JOIN)级零,那么保留表中未匹配的行作為外部行添加到虛擬表VT2中断医,產(chǎn)生虛擬表VT3。如果FROM子句含兩個以上表奏纪,則對上一個連接生成的結(jié)果表VT3和下一個表重復(fù)執(zhí)行步驟1~步驟3鉴嗤,直到處理完所有的表為止
- WHERE: 對虛擬表VT3應(yīng)用VT3應(yīng)用WEHRE過濾條件,只有符合<where_conditon>的記錄才被插入虛擬表VT4中
- GROUP BY:根據(jù)GROUP BY 子句中的列序调,對VT4中的記錄進(jìn)行分組操作醉锅,產(chǎn)生VT5
- CUBE|ROLLUP:對表VT5進(jìn)行CUBE或ROLLUP操作,產(chǎn)生表VT6
- HAVING:對虛擬表VT6應(yīng)用HAVING過濾器炕置,只有符合<having_condition>的記錄才被插入虛擬表VT7中
- SELECT:選定指定的列荣挨,插入到虛擬表VT8中
- DISTINCT:去除重復(fù)數(shù)據(jù)男韧,產(chǎn)生虛擬表VT9
- ORDER BY:將虛擬表VT9中的記錄按照<order_by_list>進(jìn)行排序操作朴摊,產(chǎn)生虛擬表VT10
- LIMIT:取出指定行的數(shù)據(jù),產(chǎn)生虛擬表VT11此虑,并返回給查詢用戶
第一步
首先我們創(chuàng)建好自己的倆個表
第二部來執(zhí)行我們需要的執(zhí)行語句
1.執(zhí)行笛卡爾積
第一部需要做的是對From子句前后的兩張表進(jìn)行笛卡爾積操作甚纲,也稱作交叉連接(Cross Join),生產(chǎn)虛擬表VT1朦前。如果FROM子句前的表中包含a行數(shù)據(jù)介杆,F(xiàn)rom子句后的表中包含b行數(shù)據(jù),那么虛擬表VT1中將包含a*b行數(shù)據(jù)韭寸。
2.應(yīng)用ON過濾器
SELECT查詢一共有3個過濾過程春哨,分別是ON,WHERE恩伺,HAVING赴背。ON是最先執(zhí)行的過濾過程。根據(jù)上一個步驟產(chǎn)生的虛擬表VT1晶渠,應(yīng)用ON進(jìn)行過濾
3.添加外部行
這一步只有在連接類型為OUTER JOIN時才發(fā)生凰荚,如LEFT OUTER JOIN,RIGHT OUTER JOIN褒脯,F(xiàn)ULL OUTER JOIN便瑟。雖然在大多數(shù)時候我們可以省略O(shè)UTER關(guān)鍵詞,但OUTER代表的就是外部行番川。LEFT OUTER JOIN把左表記為保留表到涂,RIGHT OUTER JOIN把右表記為保留表脊框,F(xiàn)ULL OUTER JOIN把左右表都記為保留表。添加外部行的工作就是在VT2表的基礎(chǔ)上添加保留表中被過濾條件過濾掉的數(shù)據(jù)养盗,非保留表的數(shù)據(jù)被賦予NULL值缚陷,最后生成虛擬表VT3
4.WEHRE條件過濾器
對上一個步驟產(chǎn)生的虛擬表VT3進(jìn)行WHERE條件過濾,只有符合<where_condition>的記錄才會輸出到虛擬表VT4中往核。
在當(dāng)前應(yīng)用WHERE過濾器時箫爷,有兩種過濾是不被允許的
由于數(shù)據(jù)還沒有分組,因此現(xiàn)在還不能再WHERE過濾器中使用where_condition=MIN(col)這類對統(tǒng)計的過濾
由于沒有進(jìn)行列的選取操作聂儒,因此在SELECT中使用列的別名也是不被允許的虎锚,如SELECT city as c FROM t WHERE c = "shanghai"是不允許出現(xiàn)的
5.進(jìn)行分組 Group By
6.應(yīng)用ROLLUP或CUBE
如果指定了ROLLUP選項(xiàng),那么將創(chuàng)建一個額外的記錄添加到虛擬表VT5的最后衩婚,并生成虛擬表VT6窜护。因?yàn)槲覀兊牟樵儾⑽从玫絉OLLUP,所以將跳過本步驟非春。
對于CUBE選項(xiàng)柱徙,MySQL數(shù)據(jù)庫雖然支持該關(guān)鍵字的解析,但是并未實(shí)現(xiàn)該功能奇昙。
7.HAVING條件過濾器
這是最后一個條件過濾器了护侮,之前已經(jīng)分別應(yīng)用了ON和WHERE過濾器。在該步驟中對于上一步產(chǎn)生的虛擬表應(yīng)用HAVING過濾器储耐,HAVING是對分組條件進(jìn)行過濾的篩序器羊初。
8.處理SELECT列表
雖然SELECT是查詢中最先被指定的部分,但是直到步驟8時才真正進(jìn)行處理什湘。在這一步中长赞,將SELECT中指定的列從上一步產(chǎn)生的虛擬表中選出
9.DISTINCT子句
如果在查詢中指定了DISTINCT子句,則會創(chuàng)建一張內(nèi)存臨時表(如果內(nèi)存中存放不下就放到磁盤上)闽撤。這張內(nèi)存臨時表的表結(jié)構(gòu)和上一步產(chǎn)生的虛擬表一樣得哆,不同的是對進(jìn)行DISTINCT操作的列增加了一個唯一索引,以此來去除重復(fù)數(shù)據(jù)哟旗。
由于在這個SQL查詢中未指定DISTINCT贩据,因此跳過本步驟。另外對使用了GROUP BY的查詢热幔,再使用DISTINCT是多余的乐设,因?yàn)橐呀?jīng)進(jìn)行分組,不會移除任何行
10.ORDER BY子句
11.LIMIT子句
在該步驟中應(yīng)用LIMIT子句绎巨,從上一步驟的虛擬表選出從指定位置開始的指定行數(shù)據(jù)近尚。對于沒有應(yīng)用ORDER BY的LIMIT子句,結(jié)果同樣可能是無序的场勤,因此LIMIT子句通常和ORDER BY子句一起使用