我有一个包含用户及其经理的表格:
|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
如果管理者的层次结构组织得很好,它就可以正常工作。但在某些情况下,我们的结构混乱,下级经理恰好是高级经理的经理:
在这种情况下,递归查询进入循环,并且在语句完成之前,最大递归100正在耗尽。我需要从查询中排除这些管理器,如果它们被选择到结果表中,以避免这些循环。
我该怎么做?
另一种可能的解决方案是在达到某个级别时从递归中退出,或者它,例如,5。但是选项(maxrecursion 5)只是设置限制,如果达到限制,查询会产生错误。
如何逐步退出递归并继续执行脚本而没有任何错误?
答案 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
答案 1 :(得分: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下编写的。根据您的数据库更改字符串的功能。