在使用Sql Server的時候,當需要遞歸的時候很多時候就會想到使用CTE。但是當遞歸層數比較多,超過了100層,或者是一個遞歸死循環的時候。執行就會爆遞歸次數已到,最多100的錯誤。
當面對第一種情況,層數超過了100,比方說用於生成數列或者日期的時候,講 maxrecursion 設置為 -1就可以解決,這個也不是問題。但是如果是死循環的話呢,就需要檢查自己數據和查詢語句的邏輯了。
這里我要說的是,假如我們在查詢的時候手動設置 maxrecursion 的時候,能不能避免死循環,只循環到某一層呢?
先給答案,是不行的,然后上例子,顯而易見,這里肯定是一個死循環,然后返回結果是醬紙的。
IF OBJECT_ID('tempdb..#ID') IS NOT NULL DROP TABLE #ID CREATE TABLE #ID (ID INT,vname VARCHAR(50)) INSERT INTO #ID ( ID, vname ) VALUES ( 1, 'A'),(2,'B'),(3,'B'),(4,'B'),(5,'B'),(6,'B'),(7,'B') ;WITH CTE AS ( SELECT * FROM #ID UNION ALL SELECT ID+1,CTE.vname FROM CTE ) SELECT * FROM CTE
顯示出來第一層,然后就是一直遞歸最后一條數據。可以看出來,並不是每一條數據手牽手遞歸一層,然后又手牽手遞歸一層的效果,而是先游標遞歸完最后一條,然后反推回來最上面一條的。
在這個原因,所以你看到這個簡單的例子里面,就不存在遞歸A~F的情況。
好,然后回答前面的問題,使用 maxrecursion 的值來控制遞歸次數是不可取的,唯一有用的地方就是減少了遞歸次數,有效減少數據庫的開銷。
但是如果要控制遞歸次數的話,可以做一個小改動,就可以控制遞歸次數
IF OBJECT_ID('tempdb..#ID') IS NOT NULL DROP TABLE #ID CREATE TABLE #ID (ID INT,vname VARCHAR(50)) INSERT INTO #ID ( ID, vname ) VALUES ( 1, 'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E'),(6,'F'),(7,'G') ;WITH CTE AS ( SELECT *,1 AS Lv FROM #ID UNION ALL SELECT ID+1,CTE.vname,Lv+1 FROM CTE WHERE CTE.Lv < 3 ) SELECT * FROM CTE
這樣的話,就可以控制遞歸次數了。這個小技巧還是挺實用的,分享給大家