准備數據
Sql腳本如下,兩張表,一張客戶表Customers只包含customerid和city字段,一張訂單表Orders包含orderid和customerid(關聯Customers的customerid字段)

IF OBJECT_ID('dbo.Orders') IS NOT NULL DROP TABLE dbo.Orders; IF OBJECT_ID('dbo.Customers') IS NOT NULL DROP TABLE dbo.Customers; GO CREATE TABLE dbo.Customers ( customerid CHAR(5) NOT NULL PRIMARY KEY, city VARCHAR(10) NOT NULL ); CREATE TABLE dbo.Orders ( orderid INT NOT NULL PRIMARY KEY, customerid CHAR(5) NULL REFERENCES Customers(customerid) ); GO INSERT INTO dbo.Customers(customerid, city) VALUES('FISSA', 'Madrid'); INSERT INTO dbo.Customers(customerid, city) VALUES('FRNDO', 'Madrid'); INSERT INTO dbo.Customers(customerid, city) VALUES('KRLOS', 'Madrid'); INSERT INTO dbo.Customers(customerid, city) VALUES('MRPHS', 'Zion'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(1, 'FRNDO'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(2, 'FRNDO'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(3, 'KRLOS'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(4, 'KRLOS'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(5, 'KRLOS'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(6, 'MRPHS'); INSERT INTO dbo.Orders(orderid, customerid) VALUES(7, NULL);
對於一條Sql語句(主要指的是查詢語句)的執行順序,很多開發人員並不是十分的了解,哪怕已經工作幾年的所謂高級開發人員也是一樣,對於他們來說,只關心最終得到的結果,並不關心中間的過程,那么了解SqlServer的語句執行過程到底有什么用處的?
1、如果不了解執行過程,下面的Sql語句你認為結果是一樣的嗎?
select * from Customers AS C left join Orders AS O On C.customerid=O.customerid and C.customerid='FRNDO' where city ='Madrid' select * from Customers AS C left join Orders AS O On C.customerid=O.customerid where city ='Madrid' and C.customerid='FRNDO'
如果你了解Sql的執行順序,這個問題就不難解釋了,只不過是On語句和Where語句誰先執行以及On和Where之間是否還有其它執行步驟?
2、下面這兩條語句,第一個會提示列where語句中的myorder(select 中起的別名)無效,第二條是可以正常執行的,那問題來了,為什么order by語句中可以使用myorder列而where中就不可以呢?
select C.customerid,C.city,O.orderid as myorder from Customers AS C left join Orders AS O On C.customerid=O.customerid where myorder >3 order by myorder desc select C.customerid,C.city,O.orderid as myorder from Customers AS C left join Orders AS O On C.customerid=O.customerid where O.orderid >3 order by myorder desc
Sql語句邏輯執行順序
一條常用的查詢語句應當是包含了下面的幾條命令
select distinct top 3 C.customerid, count(O.orderid) as orderCount from Customers as C left join Orders as O ON C.customerid=O.customerid where C.city='Madrid' group by C.customerid having count(O.orderid)>1 order by orderCount desc
1、From階段
From階段主要是標識數據來源,處理表運算符(join、apply,pivot等,本文只針對join講解),以及各個子階段(包括笛卡爾積、ON篩選器應用、添加外部行[只有外鏈接才有]);
1.1 join階段 join分為cross join、inner join、[left join、right join,full join]
cross join只是簡單的進行笛卡爾積,如上面的兩張表cross join之后的結果如下圖(左一);
inner join是在cross join的基礎上加入了ON篩選條件,如圖(左二和左三),只有ON(C.customerId=O.customerId)為Ture的才會返回
left join 是在 inner join的基礎上添加了外部行,在ON階段獲取的數據基礎上添加左表(Customer表)中的未滿足ON篩選條件的所有行(未在ON階段出現的),如圖(左四)
2、Where 階段
where 階段就是對From階段得到的虛擬表進行進一步的過濾和篩選,和Join中的ON篩選類似,只是比ON篩選器執行的晚,特別對於外鏈接來說,ON篩選和Where篩選中間還多了一步添加外部行,這里應該可以解釋本文開篇提到的第一個問題了。
3、Group By
Group By 只是按照指定的列名對第二步(如果存在)Where階段得到的虛擬表進行分組,每個分組只有一條數據,一般都是使用聚合函數來計算一些數據,比如上面例子中用按照CustomerId進行分組,用Count獲取每個客戶的訂單數量,然后按照訂單數量倒序去排名前三的客戶。
4、Having
Having階段是在第三步(如果存在)分組之后再一次進行過濾,也就是對Group By階段得到的虛擬結果集進行進一步的篩選過濾,過程和ON、Where類似,只能用在Group BY 之后。
5、Select
Select 階段則是針對第四步(如果存在)獲取的虛擬表的基礎上選擇需要的列,也就是最終要返回的列,看到這里是不是明白了本文開篇提到的第二個問題,為什么Select中的別名不能再Wher階段使用,因為Where早於Select,
Select又可以分為幾個子階段,包括(5.1計算表達式,5.2 Distinct,5.3 Top)
6、Order By
Order By 階段是整個查詢的最后階段也就是根據指定的列名對Select階段進行排序,這也就是為什么在Order By語句中可以用Select階段起的別名的原因,不過Order By階段和上面的5個階段有個很大的區別,Order By階段返回的數據集是游標,而上面的5個階段生成的都是數據表,理解這點很重要,SqlServer的理論基礎是集合論,集合中的行之間沒有預先定義順序,它只是成員之間的邏輯組合,成員之間的順序無關緊要,而對於帶有Order By的查詢語句,是返回了一個按照特定的順尋組成的一個對象,成為游標。
最后附上一張Sql語句的執行流程圖(圖片來源Sql08解密)
總結
不知不覺已經寫了將近3個小時了,本文簡單介紹SqlServer中個語句的執行過程,只有理解的個語句的執行過程,才能寫出更加准確,更加高效的Sql命令。