2017-02-10 67 views
1

我有用户和他们的经理表:SQL - 如何避免最大递归的递归查询使用CTE

|ID | Title  | Manager | 
|1 | Manager 1 | 4  | 
|2 | Manager 2 | 1  | 
|3 | Manager 3 | 1  | 
|4 | Manager 4 | 2  | 
|5 | Manager 5 | 3  | 
... 
|10 | Manager 10| NULL | 
|11 | Manager 11| 10  | 

我有一个返回所有经理的ID在层次结构开始用一个简单的递归查询给出最高管理者ID及以下:

DECLARE @Managers TABLE (ManagerID int) 
DECLARE @ManagerID int = 1 
     BEGIN 
      ;WITH ManagerCTE AS (
           SELECT ID FROM tblUsers WHERE ID = @ManagerID 
           UNION ALL 
           SELECT chld.ID FROM tblUsers chld 
           INNER JOIN ManagerCTE items ON chld.Manager = items.ID 
           ) 
      INSERT INTO @Managers 
      SELECT ID FROM ManagerCTE 
     END 
SELECT * FROM @Managers 

而且,如果经理层级结构组织良好,但在某些情况下,我们已经杂乱无章的结构,其中下部经理恰好是上经理的经理: enter image description here

在这种情况下,递归查询进入一个循环和最大递归100被语句完成之前耗尽。我需要将这些管理器从查询中排除,如果它们已被选中到结果表中以避免这些循环。

我该怎么做?

另一种可能的解决方案是在达到某个级别或它时(例如,5)从递归中退出。但选项(maxrecursion 5)仅设置限制,并且如果达到限制,则查询会产生错误。

如何退出递归并继续执行没有任何错误的脚本?

+0

如果您关注是关于限制100你可以给最大限制'从ManagerCTE 选项(maxrecursion 0)' –

+0

不应该在数据库中修复这个问题吗?在我看来,这是一种不能(或者至少不应该)存在的情况。 – HoneyBadger

+0

如果我放置(maxrecursion 0),这将不会被修复,因为我们会得到一个无限循环。 –

回答

0

WITH试试这个:

SELECT ID, ID::text as ids FROM tblUsers WHERE ID = @ManagerID 
UNION ALL 
SELECT chld.ID FROM tblUsers chld, items.ids || ',' || chld.ID::text as ids 
INNER JOIN ManagerCTE items ON chld.Manager = items.ID AND chld.ID::text not like '%'||items.ids||'%' 

守则下PostgreSQL的写入。根据你的数据库更改字符串的功能。

+0

这是行不通的,因为我收到一个错误:“公用表表达式'ManagerCTE'的递归成员有多个递归引用” –

+0

对不起,我需要记住的一个时刻,我已经完成了这项工作 –

+0

您使用哪个数据库? –

1

至于说在我的意见,你可以检查访问节点as I do it here通过将它们存储在一个成长路径字符串,或者你可以用递归CTE这样的限制递归的深度:

SELECT 1 AS CurrentLevel,ID FROM tblUsers WHERE ID = @ManagerID 
UNION ALL 
SELECT items.CurrentLevel+1,chld.ID FROM tblUsers chld 
INNER JOIN ManagerCTE items ON chld.Manager = items.ID 
WHERE items.CurrentLevel<=5 
+0

谢谢,我可能会限制递归的深度。 –