標籤:SQL SERVER/MSSQL SERVER/數據庫/DBA/查詢步驟算法
查詢步驟是很基礎也挺重要的一部分,可是我仍是在周圍發現有些人雖然會語法,可是對於其中的步驟不是很清楚,這裏就來分解一下其中的步驟,在技術內幕系列裏面都會有講到。數據庫
目錄函數
(1)FROM <LEFT_TABLE> <JOIN_TYPE> JOIN <RIGHT_TABLE> ON <ON_PREDICATE> |<LEFT_TABLE> <APPLY_TYPE> APPLY <RIGHT_TABLE_EXPRESSION> AS <alias> |<LEFT_TABLE> pivot(<pivot_specification>) AS <alias> |<LEFT_TABLE> UNPIVOT(<unpivot_specification>) AS <alias> (2)WHERE<where_predicate> (3)GROUP BY<group_by_specification> (4)HAVING<having_predicate> (5)SELECT <DISTINCT> <TOP> <select_list> (6)ORDER BY<order_by_list>
--建立測試表 --建立顧客表 CREATE TABLE Customers (custid INT NOT NULL PRIMARY KEY, city NVARCHAR(20) NOT NULL ) go INSERT INTO Customers VALUES(1,'深圳'),(2,'廣州'),(3,'武漢'),(4,'上海'),(5,'北京') --建立訂單表 CREATE TABLE Orders (orderid INT NOT NULL PRIMARY KEY IDENTITY(1000,1), custid INT NOT NULL, orderdate DATETIME NOT NULL ) GO INSERT INTO Orders(custid,orderdate)values(1,'2013-10-1 00:00:00'),(1,'2013-10-2 00:00:00'),(1,'2013-10-3 00:00:00'),(1,'2013-10-4 00:00:00'),(2,'2013-10-1 00:00:00'),(2,'2013-10-3 00:00:00'),(2,'2013-10-5 00:00:00'),(3,'2013-10-3 00:00:00'),(3,'2013-10-7 00:00:00'),(4,'2013-10-1 00:00:00') --建立訂單明細表 CREATE TABLE [OrderDetails]( [orderid] [int] NOT NULL, [productid] [int] NOT NULL, [unitprice] [money] NOT NULL, [qty] [smallint] NOT NULL CONSTRAINT [PK_OrderDetails] PRIMARY KEY CLUSTERED ( [orderid] ASC, [productid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO INSERT INTO OrderDetails VALUES(1000,10,5.00,1),(1000,14,6.00,2),(1001,10,5.31,3),(1001,11,5.22,1),(1001,12,3.20,3),(1001,13,4.10,2),(1002,11,7.00,1),(1003,12,8.00,5),(1004,13,8.41,1),(1004,11,6.65,1),(1005,18,7.41,1),(1006,17,10.00,1)
--查詢深圳、廣州每個顧客每筆金額大於10的訂單,並按訂單價格倒序排序 SELECT TA.custid,TB.orderid,SUM(tc.unitprice*tc.qty) AS price FROM Customers TA LEFT JOIN Orders TB ON TA.custid=TB.custid LEFT JOIN OrderDetails TC ON TB.orderid=tc.orderid WHERE TA.city IN('深圳','廣州') GROUP BY TA.custid,TB.orderid HAVING SUM(tc.unitprice*tc.qty)>10 ORDER BY price DESC
這一步是一個T-SQL語句的開始,通常緊接着FROM的這個表被稱做左表,例如a inner join b inner join c,首先a做爲左表而後關聯b,a和b關聯的結果做爲下一個運算的左表關聯c。在FROM階段涉及的表運算會有JOIN(LEFT JOIN,RIGHT JOIN,FULL JOIN),APPLY(CROSS APPLY,OUTER APPLY),PIVOT,UNPIVOT測試
對於上面的查詢例子:FROM Customers TA LEFT JOIN Orders TB ON TA.custid=TB.custid的左鏈接的分解是這樣的 spa
第一步交叉鏈接、SELECT * FROM Customers TA CROSS JOIN Orders TB---首先進行交叉鏈接獲得的行數是5*10=50行code
第二步ON篩選、將TA.custid=TB.custid之外的結果排除,能夠等價於SELECT * FROM Customers TA CROSS JOIN Orders TB WHERE TA.custid=TB.custid
第三步、將主表(左邊的表)不在第二步的行加上,能夠等價於 SELECT * FROM Customers TA CROSS JOIN Orders TB WHERE TA.custid=TB.custid union all SELECT * FROM Customers TA LEFT JOIN Orders TB ON TA.custid=TB.custid WHERE TB.custid IS NULLblog
因此其它幾個表運算只要你們知道怎麼使用就能夠了,你們只要明白它在T-SQL語句中的位置就行。排序
這裏要注意一點:你們理解了JEFT JOIN的原理以後就明白"on"篩選對查詢的刪除不是最終的,在上面的第三步會把主表的一些行又添加上來,因此咱們有時候寫LEFT JOIN的時候有的人不太明白爲何ON 後面加AND和把AND放在WHERE裏面的獲得的結果不同,就是這個原理了,WHERE操做對查詢的刪除纔是最終的。內存
固然後面的有些階段都是可選的也就是有的查詢不必定會用到,可是這裏爲了講述整個過程,因此就一步一步的來說,在FROM 階段結束以後會生成一張虛擬表,進入第二階段也就是WHERE階段,在WHERE階段是對前一階段(FROM階段)結果返回行進行篩選,例如上面的查詢篩選城市是‘深圳’,‘廣州’的顧客ci
因此爲何把select步驟裏面生成的列寫在where裏面沒法識別就是由於where在select操做以前。
GROUP BY 操做是分組操做,確保進行分組的屬性集每個組都是惟一的,GROUP BY 操做的數據是WHERE階段篩選以後的數據,例如上面的查詢例子是將custid,orderid做爲一行來進行分組,上面的例子是每個顧客每一筆訂單的消費金額。
HAVING階段是在GOUP BY 階段返回TURE以後纔會有這步操做,HAVING是對上一步的分組以後的數據進行篩選的步驟,例如篩選消費訂單金額大於10的顧客訂單
select階段是返回上一步操做獲得的虛擬表的數據列,因此也就是爲何存在group by的分組查詢,select裏面的列跟group by 的分組列須要一致的緣由了,聚會函數生成的列除外,由於select查詢的基礎列就是來源於前面的步驟,select階段會涉及到去重複distinct固然若是前面存在分組也就不存在重複了,TOP操做,還有一些字段之間的算法運算,子查詢等等。
這一步是整個過程的最後一步操做,由於它在SELECT階段以後,因此對於SELECT裏面生成的字段別名在ORDER BY 中可使用別名,對於一張表,表表明的是集合,集合是沒有順序的,當一個查詢帶有ORDER BY時咱們能夠把它理解成遊標,遊標是有特定的排序,因此爲何一個查詢加上ORDER BY 操做以後會變的很慢了,由於它須要進行排序操做。
---當查詢沒有排序時 SELECT * FROM Orders
---當查詢有排序時 SELECT * FROM Orders ORDER BY CUSTID
order by 是保證結果排序順序,top是一個邏輯運算操做
對於一個沒有外部查詢的語句,order by 操做既能保證結果根據制定條件的排序,又能知足TOP的邏輯運算(查詢最小的三個orderid) SELECT TOP (3) * FROM Orders ORDER BY ORDERID
對於存在外部查詢時,order by在做用僅僅是保證top的邏輯結果的正確輸出,而不能保證查詢結果的排序,雖然咱們可能查詢出的結果是按照這個方式排序。 ---當不指定TOP時報錯 SELECT * FROM(SELECT custid,orderid,orderdate FROM Orders ORDER BY orderdate DESC) AS A ---當指定 SELECT * FROM(SELECT TOP (3) custid,orderid,orderdate FROM Orders ORDER BY orderdate DESC) AS A
理解完了整個查詢的過程,也就能能理解爲何SQLServer這麼耗內存了,每一步的操做都是生成一張虛擬表進入下一步操做,理解了整個查詢過程 以後對咱們理解T-SQL語法頗有幫助,同時也有利於分析語句。
若是文章對你們有幫助,但願你們能給個贊,謝謝!!!
備註: 做者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接,不然保留追究責任的權利。 《歡迎交流討論》 |