SQL 遞歸查詢,意淫CTE遞歸的執行步驟


 

今天用到了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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM