customerid | city |
FISSA | Madrid |
FRNDO | Madrid |
KRLOS | Madrid |
MRPHS | Zion |
創(chuàng)建一個(gè)Orders表,插入如下數(shù)據(jù):
orderid | customerid |
1 | FRNDO |
2 | FRNDO |
3 | KRLOS |
4 | KRLOS |
5 | KRLOS |
6 | MRPHS |
7 | NULL |
假如我們想要查詢來(lái)自Madrid的,訂單數(shù)小于3的客戶,并把他們的訂單數(shù)顯示出來(lái),結(jié)果按照訂單數(shù)從小到大進(jìn)行排序。
customerid | numorders |
FISSA | 0 |
FRNDO | 2 |
下面我們會(huì)詳細(xì)的講述sql是怎樣計(jì)算出這個(gè)結(jié)果的:
FROM子句FROM子句標(biāo)識(shí)了需要查詢的表,如果指定了表操作,會(huì)從左到右的處理,每一個(gè)基于一個(gè)或者兩個(gè)表的表操作都會(huì)返回一個(gè)輸出表。左邊表的輸出結(jié)果會(huì)作為下一個(gè)表操作的輸入結(jié)果。例如,交表相關(guān)的操作有 (1-J1)笛卡爾積,(1-J2)ON過(guò)濾器,(1-J3)添加外部列。FROM句子生成虛擬表VT1。
Step 1-J1:執(zhí)行笛卡爾積(CROSS JOIN)笛卡爾積會(huì)把左右兩個(gè)表每一行所有可能的組合都列出來(lái)生成表VT1-J1,如果左表有m列,右表有n列,那么笛卡爾積之后生成的VT1-J1表將會(huì)有m×n列。
Step 1-J1這個(gè)步驟等價(jià)于執(zhí)行:
SELECT * from Customers C CROSS JOIN Orders O
執(zhí)行結(jié)果為:(共有4×7列)
C.customerid | C.city | O.orderid | O.customerid |
FISSA | Madrid | 1 | FRNDO |
FISSA | Madrid | 2 | FRNDO |
FISSA | Madrid | 3 | KRLOS |
FISSA | Madrid | 4 | KRLOS |
FISSA | Madrid | 5 | KRLOS |
FISSA | Madrid | 6 | MRPHS |
FISSA | Madrid | 7 | NULL |
FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO |
FRNDO | Madrid | 3 | KRLOS |
FRNDO | Madrid | 4 | KRLOS |
FRNDO | Madrid | 5 | KRLOS |
FRNDO | Madrid | 6 | MRPHS |
FRNDO | Madrid | 7 | NULL |
KRLOS | Madrid | 1 | FRNDO |
KRLOS | Madrid | 2 | FRNDO |
KRLOS | Madrid | 3 | KRLOS |
KRLOS | Madrid | 4 | KRLOS |
KRLOS | Madrid | 5 | KRLOS |
KRLOS | Madrid | 6 | MRPHS |
KRLOS | Madrid | 7 | NULL |
MRPHS | Zion | 1 | FRNDO |
MRPHS | Zion | 2 | FRNDO |
MRPHS | Zion | 3 | KRLOS |
MRPHS | Zion | 4 | KRLOS |
MRPHS | Zion | 5 | KRLOS |
MRPHS | Zion | 6 | MRPHS |
MRPHS | Zion | 7 | NULL |
ON過(guò)濾條件是sql的三個(gè)過(guò)濾條件(ON,WHERE,HAVING)中最先執(zhí)行的,ON過(guò)濾條件應(yīng)用于前一步生成的虛擬表(VT1-J1),滿足ON過(guò)濾條件的行會(huì)被加入到虛擬表VT1-J2中。在應(yīng)用了ON 過(guò)濾之后,生成的VT1-J2表如下所示:
C.customerid | C.city | O.orderid | O.customerid |
FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO |
KRLOS | Madrid | 3 | KRLOS |
KRLOS | Madrid | 4 | KRLOS |
KRLOS | Madrid | 5 | KRLOS |
MRPHS | Zion | 6 | MRPHS |
這個(gè)步驟只會(huì)出現(xiàn)在使用了外連接的情況。對(duì)于外連接(LEFT,RIGHT, or FULL),你可以標(biāo)記一個(gè)或者兩個(gè)表作為保留表。作為保留表意味著你希望這個(gè)表里面的所有列都被返回,即使它里面的數(shù)據(jù)不滿足ON子句的過(guò)濾條件。LEFT OUTER JOIN 把左邊的表標(biāo)記為保留表,RIGHTOUTER JOIN把右邊的表作為保留表,F(xiàn)ULL OUTER JOIN把兩個(gè)表都標(biāo)記為保留表.Step 1-J3為根據(jù)VT1-J2中的虛擬表,添加了保留表中不滿足ON 條件的列,在未保留表中沒有對(duì)應(yīng)的列,因此標(biāo)記為NULL。這個(gè)過(guò)程生成了虛擬表VT1-J3。
C.customerid | C.city | O.orderid | O.customerid |
FISSA | Madrid | NULL | NULL |
FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO |
KRLOS | Madrid | 3 | KRLOS |
KRLOS | Madrid | 4 | KRLOS |
KRLOS | Madrid | 5 | KRLOS |
MRPHS | Zion | 6 | MRPHS |
如果FROM子句中有多個(gè)表操作運(yùn)算,sql會(huì)按照從左到右的順序處理,左邊生成的臨時(shí)表結(jié)果作為右邊表的輸入表。
Step 2 WHERE 子句WHERE過(guò)濾被應(yīng)用到前一步生成的臨時(shí)表中,根據(jù)WHERE過(guò)濾條件生成臨時(shí)表VT2。
注意:由于數(shù)據(jù)現(xiàn)在還沒有被分組,因此現(xiàn)在你不能使用聚合運(yùn)算-例如:你不能使用這樣的句子 WHERE orderdate = MAX(orderdate)。另外你也不能使用SELECT子句中創(chuàng)建的變量別名,因?yàn)楝F(xiàn)在還沒有處理SELECT子句-例如你不能寫這樣的句子:SELECT YEAR(orderdate) AS orderyear . . . WHERE orderyear > 2008.
應(yīng)用這個(gè)過(guò)濾
WHERE C.city = 'Madrid'
這時(shí)生成的臨時(shí)表VT2的內(nèi)容如下:
C.customerid | C.city | O.orderid | O.customerid |
FISSA | Madrid | NULL | NULL |
FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO |
KRLOS | Madrid | 3 | KRLOS |
KRLOS | Madrid | 4 | KRLOS |
KRLOS | Madrid | 5 | KRLOS |
在這個(gè)例子中,你需要在ON子句中使用ON C.customerid = O.customerid過(guò)濾,沒有訂單的客戶在1-J2這一步中被過(guò)濾掉,但是在1-J3這一步中作為外部列又被加回來(lái)。但是,由于你只想返回來(lái)自Madrid的客戶,因此你需要在WHERE子句中過(guò)濾城市(WHERE C.city = ‘Madrid'),如果你放在ON過(guò)濾中,不屬于Madrid的客戶在添加外部列中會(huì)被添加回來(lái)。
關(guān)于ON 和 WHERE 的區(qū)別需要在這里說(shuō)明一下,ON 和WHERE 的主要區(qū)別在于 ON 實(shí)在添加外部列之前進(jìn)行過(guò)濾,WHERE 是在之后。ON過(guò)濾掉的列會(huì)在1-J3中添加回來(lái)。如果你不需要添加外部列,那么這兩個(gè)過(guò)濾是相同的。
Step 3 GROUP BY子句這個(gè)子句會(huì)把前一步中生成的臨時(shí)表中的數(shù)據(jù)進(jìn)行分組,每一行都會(huì)分到并且只分到一個(gè)組里,生成虛擬表VT3。VT3表中包含了VT2表中所有的數(shù)據(jù),和分組標(biāo)識(shí)符。
這是生成的臨時(shí)表VT3的內(nèi)容如下:
Groups C.customerid |
C.customerid | C.city | O.orderid | O.customerid |
FISSA | FISSA | Madrid | NULL | NULL |
FRNDO | FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO | |
KRLOS | Madrid | 3 | KRLOS | |
KRLOS | KRLOS | Madrid | 4 | KRLOS |
KRLOS | Madrid | 5 | KRLOS |
sql最終返回的結(jié)果中,每一個(gè)分組必須只能返回一行(除非被過(guò)濾掉),因此當(dāng)一個(gè)sql語(yǔ)句中使用了GROUP BY時(shí),在GROUP BY后面處理的子句,如SELECT,HAVING子句等,只能使用出現(xiàn)在GROUP BY后面的列,對(duì)于沒有出現(xiàn)GROUP BY后面的列必須使用聚合函數(shù)(如 MAX ,MIN,COUNT,AVG等),保證每一個(gè)GROUP只返回一行。
Step 4 HAVING子句HAVING子句用來(lái)過(guò)濾前一步生成的臨時(shí)表,并且只作用于分組后的數(shù)據(jù),滿足HAVING條件的GROUP被添加到虛擬表VT4中。
當(dāng)應(yīng)用了這個(gè)過(guò)濾:
Groups C.customerid |
C.customerid | C.city | O.orderid | O.customerid |
FISSA | FISSA | Madrid | NULL | NULL |
FRNDO | FRNDO | Madrid | 1 | FRNDO |
FRNDO | Madrid | 2 | FRNDO |
需要注意的一點(diǎn)是,這里面使用的是COUNT(O.orderid),而不是COUNT(*),由于這個(gè)查詢中添加了外部列,COUNT方法會(huì)忽略NULL的列,導(dǎo)致出現(xiàn)了你不想要的結(jié)果。
Step 5 SELECT 子句盡管出現(xiàn)在sql語(yǔ)句的最前面,SELECT在第五步的時(shí)候才被處理,SELECT子句返回的表會(huì)最終返回給調(diào)用者。這個(gè)子句包含三個(gè)子階段:(5-1)計(jì)算表達(dá)式,(5-2) 處理DISTINCT,(5-3)應(yīng)用TOP過(guò)濾。
Step 5-1 計(jì)算表達(dá)式
SELECT子句中的表達(dá)式可以返回或者操作前一步表中返回的基本列。如果這個(gè)sql語(yǔ)句是一個(gè)聚合查詢,在Step 3之后,你只能使用GROUP BY中的列,對(duì)不屬于GROUP集合中的列必須使用聚合運(yùn)算。不屬于FROM表中基本列的必須為其起一個(gè)別名,如YEAR(orderdate) AS orderyear。
注意:在SELECT子句中創(chuàng)建的別名,不能在之前的Step中使用,即使在SELECT子句中也不能。原因是sql的很多操作是同時(shí)操作(all at once operation),至于什么是all-at-once operation這里就不再介紹了。因此,SELECT子句中創(chuàng)建的別名只能在后面的子句中使用,如ORDER BY。例如:SELECT YEAR(orderdate) AS orderyear . . . ORDER BY orderyear。
在這個(gè)例子中:
C.customerid | numorders |
FIFSSA | 0 |
FRNDO | 2 |
Step 5-2:應(yīng)用DISTINCT子句
如果sql語(yǔ)句中使用了DISTINCT,sql會(huì)把重復(fù)列去掉,生成虛擬表VT5-2。
Step 5-3:應(yīng)用TOP選項(xiàng)
TOP選項(xiàng)是T-SQL提供的一個(gè)功能,用來(lái)表示顯示多少行?;贠RDER BY子句定義的順序,指定個(gè)數(shù)的列會(huì)被查詢出來(lái)。這個(gè)過(guò)程生成虛擬表VT5-3。
正如上文提到的,這一步依賴于ORDER BY定義的順序來(lái)決定哪些列應(yīng)該顯示在前面。如果你沒有指定結(jié)果的ORDER BY順序,也沒有使用WITH TIES子句 ,每一次的返回結(jié)果可能會(huì)不一致。
在我們的例子中,Step 5-3被省略了,因?yàn)槲覀儧]有使用TOP關(guān)鍵字。
Step 6:ORDER BY子句前一步返回的虛擬表在這一步被排序,根據(jù)ORDER BY子句指定的順序,返回游標(biāo)VC6。ORDER BY子句也是唯一一個(gè)可以使用SELECT子句創(chuàng)建的別名的地方。
注意:這一步和之前不同的地方在于,這一步返回的結(jié)果是一個(gè)游標(biāo),而不是表。sql是基于集合理論的,一個(gè)集合沒有對(duì)他的行定義順序,它只是一個(gè)成員的邏輯集合,因此成員的順序并不重要。帶有ORDER BY子句的sql返回一個(gè)按照特定序列組織每一行的對(duì)象。ANSI 把這樣的一個(gè)對(duì)象叫游標(biāo)。理解這一點(diǎn)對(duì)你了解sql很重要。
上面的步驟如圖所示:本書中主要內(nèi)容是參照 Inside Microsoft SQL Server 2008:T-SQL Query,中的內(nèi)容,大家如果想深入了解sql查詢相關(guān)的知識(shí),可以找這本書看看,我這有英文原版的pdf,需要的可以找我要。
標(biāo)簽:貴州 新鄉(xiāng) 拉薩 上海 呼和浩特 江蘇 重慶 昭通
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《SQL語(yǔ)句的各個(gè)關(guān)鍵字的解析過(guò)程詳細(xì)總結(jié)》,本文關(guān)鍵詞 SQL,語(yǔ)句,的,各個(gè),關(guān)鍵字,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。