今天用到了sql的遞歸查詢。遞歸查詢是CTE語句with xx as(....)實現的。
假如表Category數據如下。
我們想查找機槍這個子分類極其層次關系(通過子節點,查詢所有層級節點)。以下是查詢語句
WITH tt AS ( SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=15 --定位點成員 UNION ALL SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --遞歸成員 ) SELECT * FROM tt
執行結果
CTE遞歸說明:
上面的腳本,我注明了定位點成員,和遞歸成員。
定位點成員形成了查詢的基本結果集。其實就是你用於查詢的"引子"數據。在遞歸cte開始執行時,第一次執行,會先執行定位成員,並得到寄出結果集。
遞歸成員是每次遞歸執行的語句。個人意淫,每次遞歸時,是把上一次遞歸查詢得出的結果集傳遞給遞歸語句,並繼續執行遞歸
在遞歸時,如果上一次查詢沒有返回結果集,則終止遞歸。(這點讓我糾結很久,因為沒有顯示的著名何時結束遞歸~)
意淫的執行步驟--------------------
首先執行定位成員:
SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46
並得到了結果集:
然后執行第一次遞歸:
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId
執行遞歸時,join了 cte 語句本身,就是tt,join里的語句跟with as里的語句一樣。其實語句可以意淫成醬紫
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( --SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=15 華麗的忽略掉了 --UNION ALL 華麗的忽略掉了 SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我們繼續遞歸~ )tt ON tt.Parent=c.CategoryId
這次遞歸可以拆分成兩個操作,查詢結果和繼續遞歸。
1.因為是第一次遞歸,所以將執行定位成員得出的結果集帶入,進行查詢。其實執行的是醬紫
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId
發現有結果:
則繼續進行遞歸:
遞歸時語句還是醬紫:
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( --SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=15 華麗的忽略掉了 --UNION ALL 華麗的忽略掉了 SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN tt ON tt.Parent=c.CategoryId --我們繼續遞歸 )tt ON tt.Parent=c.CategoryId
這次遞歸查詢,所用的結果集是上次遞歸查詢得出的(不再是定位成員的結果集了)。就是用的下面這個結果集
執行語句是醬紫的
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId )tt ON tt.Parent=c.CategoryId
第一層join的數據是上次遞歸查詢的語句。
發現有結果:
ok繼續遞歸吧
繼續上面的步驟,帶入上次查詢的結果集進行查詢。
執行語句其實是醬紫:
SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT c.CategoryId,c.Name,c.Parent,tt.level+1 level FROM Category c JOIN ( SELECT CategoryId,Name,Parent,0 level FROM dbo.Category WHERE CategoryId=46 )tt ON tt.Parent=c.CategoryId )tt ON tt.Parent=c.CategoryId )tt ON tt.Parent=c.CategoryId
得出的結果集:
啥也木有,終止遞歸。
然后用union all 把每次遞歸的結果集合起來。得出了最終的查詢結果。
這個步驟是意淫的,我還設想了其他的方式。但在終止遞歸上都存在問題,所以最終把文章寫成醬紫。
參考文章:https://www.cnblogs.com/youngmin/p/6256478.html