CTE递归 MAXRECURSION 遇到的问题
在使用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
这样的话,就可以控制递归次数了。这个小技巧还是挺实用的,分享给大家