遞歸查詢原理
CTE的遞歸查詢必須滿足三個條件:初始條件,遞歸調用表達式,終止條件;CTE 遞歸查詢的偽代碼如下:
with cte_name as( 查詢語句 union all 查詢語句 ) select * from cte_name
1. 遞歸查詢至少包含兩個子查詢:
- 第一個子查詢稱作定點(Anchor)子查詢:定點查詢只是一個返回有效表的查詢,用於設置遞歸的初始值;
- 第二個子查詢稱作遞歸子查詢:該子查詢調用CTE名稱,觸發遞歸查詢,實際上是遞歸子查詢調用遞歸子查詢;
- 兩個子查詢使用union all,求並集;
2. CTE的遞歸終止條件
遞歸查詢沒有顯式的遞歸終止條件,只有當遞歸子查詢返回空結果集(沒有數據行返回)或是超出了遞歸次數的最大限制時,才停止遞歸。默認的遞歸查詢次數是100,可以使用查詢提示(hint):MAXRECURSION 控制遞歸的最大次數:OPTION( MAXRECURSION 16);如果允許無限制的遞歸次數,使用查詢提示:option(maxrecursion 0);當遞歸查詢達到指定或默認的 MAXRECURSION 數量限制時,SQL Server將結束查詢並返回錯誤,如下:
The statement terminated. The maximum recursion 10 has been exhausted before statement completion.
事務執行失敗,該事務包含的所有操作都被回滾。在產品環境中,慎用maxrecursion 查詢提示,推薦通過 where 條件限制遞歸的次數。
3. 遞歸步驟
step1:定點子查詢設置CTE的初始值,即CTE的初始值Set0;
遞歸調用的子查詢過程:遞歸子查詢調用遞歸子查詢;
step2:遞歸子查詢第一次調用CTE名稱,CTE名稱是指CTE的初始值Set0,第一次執行遞歸子查詢之后,CTE名稱是指結果集Set1;
step3:遞歸子查詢第二次調用CTE名稱,CTE名稱是指Set1,第二次執行遞歸子查詢之后,CTE名稱是指結果集Set2;
step4:在第N次執行遞歸子查詢時,CTE名稱是指Set(N-1),遞歸子查詢都引用前一個遞歸子查詢的結果集;
Step5:如果遞歸子查詢返回空數據行,或超出遞歸次數的最大限制,停止遞歸;
查詢示例
創建測試數據

create table Product ( FID varchar(20), DeptID varchar(20), DeptName varchar(50) ) go insert into dbo.Product (FID, DeptID, DeptName) values ('0', '999', '生產部'), ('999', '998', '沖壓車間'), ('999', '997', '組裝車間'), ('997', '996', '組裝1部'), ('997', '995', '組裝2部'),('0', '1001', '銷售部'), ('998', '998001', '沖壓1部'), ('996', '997996001', '組裝1部一組'), ('1001', '1001001', '銷售一組'), ('1001', '1001002', '銷售二組')
;with cte as( select FID, DeptID, DeptName, cast(DeptName as varchar(max)) as ReportPath, cast(row_number() over(order by FID) as varchar(max)) as LevelNum from dbo.Product where FID=0 union all select B.FID, B.DeptID, B.DeptName, B.DeptName+'-->'+A.ReportPath as ReportPath, LevelNum+'.'+cast(row_number() over(order by B.FID) as varchar(max)) as LevelNum from cte A inner join dbo.Product B on A.DeptID=B.FID ) select * from cte order by cte.LevelNum
step1:查詢FID=0,作為root node,這是遞歸查詢的起始點。
step2:迭代公式是 union all 下面的查詢語句。在查詢語句中調用中cte,而查詢語句就是cte的組成部分,即 “自己調用自己”,這就是遞歸的真諦所在。
所謂迭代,是指每一次遞歸都要調用上一次查詢的結果集,Union ALL是指每次都把結果集並在一起。
step3-N,迭代公式利用上一次查詢返回的結果集執行特定的查詢,直到CTE返回null 或達到最大的迭代次數,默認值是32。最終的結果集是迭代公式返回的各個結果集的並集,求並集是由Union All 子句定義的,並且只能使用Union ALL。