SQL 研究- Common Table Expression

Common Table Expression,簡稱 CTE,是SQL Server中的三種保存臨時結果的方法之一。另外兩種是臨時表和View,當然你也可以說View並不保存數據,從這一點上來將, CTE更像View一些。

當你的查詢需要從一個源表中統計出結果,基於這個結果再做進一步的統計,如此3次以上的話,你必然會用到View或者臨時表,現在你也可以考慮用CTE了。

 

CTE的語法相當的簡單, 如下:

With CTE的名字 AS

(

子查詢

)

Select * from CTE的名字

 

CTE可以實現很多不可思議的功能,巧妙之處在於CTE可以出現自己的子查詢裏。讓我們從簡單的問題開始。

 

先假設一個需求,貴公司的員工表存放着員工號,員工直接經理的員工號,以及員工的Title,現在需要查詢出各個員工所在的層次,從0開始。

 

於是你看到這樣的表:

create table Employee
(
MgrId int,
EmpId int,
Title nvarchar(256)
)

表中的內容如下:

NULL 1 CEO
1 2 VP
2 3 Dev Manager
2 4 QA Manager
1 5 Sales Manager
3 30 Developer
3 31 Developer
4 40 Tester
4 41 Tester

 

你期望得到這樣的結果:

NULL 1 CEO 0
1 2 VP 1
1 5 SalesManager 1
2 3 DevManager 2
2 4 QAManager 2
4 40 Tester 3
4 41 Tester 3
3 30 Developer 3
3 31 Developer 3

 

最後一列爲所得到的層次數字。

 

使用如下的SQL能得到上面的效果:

 

With DirectReports as
(
select MgrId, EmpId, Title, 0 as [Level] from Employee where MgrId is null

union all

select a.MgrId, a.EmpId, a.Title, [Level]+1 as [Level]
from Employee a join  DirectReports b on a.MgrId=b.EmpId
)
select * from DirectReports

 

爲什麼這個語句能夠沿着CEO往下一層一層走下去,最終找到所有的員工呢?

顯然要理解這一SQL必須理解包含在 as只有括號裏的嵌套查詢。它由兩個查詢結合而成:

select ..

Union All

Select..

 

這兩個Select語句在CTE中有特殊的意義。

 

第一個Select子句被稱爲 錨點 語句,它返回的結果跟普通的SQL沒有區別,在這裏返回MgrID爲null的員工。可見沒有Manager是件多麼美好的事情。

 

第二個子句就沒那麼普通了,它被稱爲 遞歸 語句,請注意到在from後面, Employee和DirectReport進行了鏈接操作。您一定會問,DirectReport的定義還沒完成,這個名字代表什麼結果呢?答案是它不只是代表了一個結果,實際上代表了一系列的結果。換句話說,在DirectReport這個名字下,包含着DirectReport0,DirectReport1,DirectReport2...這些較小的集合。

DirectReport0 是Employee和 錨點 結合的產物;

DirectReport1 是Employee和 DirectReport0 結合的產物;

依次類推, DirectReport n是Employee和DirectReport n-1結合的產物;

當DirectReport_n爲空的時候,這個過程就結束了。

 

最後 錨點和DirectReport0,DirectReport1... 的並集就是DirectReport的內容。

 

作爲一個程序員,每次看到遞歸的程序,必然會想到無限遞歸這個錯誤。爲了避免了在開發階段,無限遞歸導致數據庫的崩潰,SQL Server提供了一個QueryHint, MaxRecursion,可以控制遞歸的最大層數,如果超過這個數字而仍爲結束,則視爲代碼錯誤,強制退出。以本文所用的SQL爲例,可以如下使用MaxRecursion。

With DirectReports as
(
select MgrId, EmpId, Title, 0 as [Level] from Employee where MgrId is null

union all

select a.MgrId, a.EmpId, a.Title, [Level]+1 as [Level]
from Employee a join  DirectReports b on a.MgrId=b.EmpId
)
select * from DirectReports

Option(MaxRecursion 10) 

 

正如我之前所說, CTE能完成更多的工作,讓我們以後進一步挖掘。

 

 

發佈了36 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章