2017-04-18 162 views
0

当我在查询下运行时,我收到此错误。即使我使用选项(maxrecursion 0),它不会失败,但花了很长时间,仍然看不到它完成。所以我必须修复我的递归代码或需要相同的递归。基本上有两张桌子,一张是雇员,另一张是他们的合同。在同一家长下的每个员工可以有一份合同(父母可以有孩子可以有,但这并不重要,但他们只能有一个。这意味着同一家庭有一行(一份合同))。我需要获得所有合同号码,并为所有父母和子女提供相同的专栏。SQL - 语句完成前最大递归100已用尽

---------------------------- ¦ Contract ¦ ¦--------------¦------------¦ ¦ ID_CONTRACT ¦ ID_EMPLOYEE¦ ¦--------------¦------------¦ ¦ 1 ¦ 1 ¦ ¦--------------¦------------¦ ¦ 2 ¦ 4 ¦ ¦--------------¦------------¦ ¦ 3 ¦ 6 ¦ ¦--------------¦------------¦ ¦ 4 ¦ 7 ¦ ¦--------------¦------------¦ ¦ 5 ¦ 12 ¦ ¦--------------¦------------¦ ¦ 6 ¦ 11 ¦ ¦--------------¦------------¦

---------------------------- ¦ Employee ¦ ¦--------------¦------------¦ ¦ ID_EMPLOYEE ¦ ID_MANAGER ¦ ¦--------------¦------------¦ ¦ 1 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 2 ¦ 1 ¦ ¦--------------¦------------¦ ¦ 3 ¦ 1 ¦ ¦--------------¦------------¦ ¦ 4 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 5 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 6 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 7 ¦ 5 ¦ ¦--------------¦------------¦ ¦ 8 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 9 ¦ 5 ¦ ¦--------------¦------------¦ ¦ 10 ¦ 5 ¦ ¦--------------¦------------¦ ¦ 11 ¦ NULL ¦ ¦--------------¦------------¦ ¦ 12 ¦ NULL ¦ ¦--------------¦------------¦ 我的代码是:

 drop table #cnt 
     select DISTINCT 
      cnt.ID_CONTRACT, 
      emp.ID_EMPLOYEE, 
      emp.ID_MANAGER 
     into #cnt 
     from 
      contract cnt (NOLOCK) 
     inner join 
      employee emp (NOLOCK) ON cnt.ID_EMPLOYEE = emp.ID_EMPLOYEE 

     ;WITH contactRec AS 
      (SELECT 
       cnt.ID_CONTRACT,cnt.ID_EMPLOYEE, cnt.ID_MANAGER 
      FROM 
       #cnt cnt 
      UNION ALL 
      SELECT 
       cnt.ID_CONTRACT,emp.ID_EMPLOYEE, emp.ID_MANAGER 
      FROM 
       contactRec cnt 
      Inner join employee emp on emp.ID_MANAGER = cnt.ID_EMPLOYEE 
     ) 
      select 
       [ID_CONTRACT] 
       ID_EMPLOYEE, 
       ID_MANAGER 
      from contactRec 
+0

IS'cntrementRec'是一个错字还是这个其他表吗? – JNevill

+0

@JNevill,谢谢你的警告。这是错字。我编辑过。 –

回答

1

您可以添加一个WHERE子句的CTE的递归元素,迫使递归停止。您可能还需要添加一个“路径”字段,以便您可以识别递归循环,可导致无限递归问题:

WITH contactRec AS 
     (SELECT 
      cnt.ID_CONTRACT,cnt.ID_EMPLOYEE, cnt.ID_MANAGER, 
      1 a depth, CAST(cnt.ID_Employee + '>' cnt.ID_Manager AS VARCHAR(5000)) as path 
     FROM 
      #cnt cnt 
     UNION ALL 
     SELECT 
      cnt.ID_CONTRACT,emp.ID_EMPLOYEE, emp.ID_MANAGER, 
      depth + 1 as depth, path + '>' + emp.ID_Manager as path 
     FROM 
      contactRec cnt 
     Inner join employee emp on emp.ID_MANAGER = cnt.ID_EMPLOYEE 
     WHERE depth <= 20 /*end recursion at 20 cycles*/ 
    ) 
     select 
      [ID_CONTRACT] 
      ID_EMPLOYEE, 
      ID_MANAGER, 
      depth, 
      path 
     from contactRec; 

现在它将会为20次死亡,你将有一个深度和路径指示,以帮助给关于你为什么处于无限循环的线索。

+0

其实我没有很多亲子关卡。我有最多3个层次。但为什么我必须在一定的周期内死亡?有任何其他方式来解决这个问题,或者总是不得不放置where子句来阻止它。 BTW代码工作正常,我测试了几行,但我需要测试更多的明天,并会接受它作为答案,如果无法找到任何错误。非常感谢。 –

+0

递归会自行停止,但您可能会遇到类似如下情况:employeeA向employeeB报告,employeeC报告给employeeA,后者向employeeA报告......并且无限循环。我发布的代码将帮助您确定您的层次结构的哪一段导致了无限循环。我不能彻底解决问题,因为问题很可能出现在您的数据中。上面的代码为您提供了查找它的工具,以便您可以修复数据或添加代码以防止它发生。 – JNevill

+0

我发现我也不得不在CTE的递归部分使用CAST(... AS VARCHAR(5000))AS Path –

0

我无法用您提供的架构和数据生成maxrecursion错误。但是,我注意到一件事可能会导致您的递归问题。递归CTE的一般形式是:

with cte as (

    «base case» 

    UNION ALL 

    «recursive query» 
) 
select * 
from cte 

(其中,顺便说一句,你有,我只是想引用我的观察以上)。在您的基本情况下,您正在选择所有员工。通常所做的是选择顶级或底级员工,然后在递归时降低层级或分别增加(分别)。在你的具体情况下,对我来说(从头到尾)是有意义的,因为顶级员工很容易识别。具体来说,您的基本情况发生变化的:

SELECT cnt.ID_CONTRACT , 
     cnt.ID_EMPLOYEE , 
     cnt.ID_MANAGER 
FROM  #cnt cnt 

SELECT cnt.ID_CONTRACT , 
     cnt.ID_EMPLOYEE , 
     cnt.ID_MANAGER 
FROM #cnt cnt 
WHERE ID_MANAGER IS NULL 

但即使这样,也不能解释为什么你打一个递归限制。你确定你的数据是非循环的(也就是说,你没有类似1→2→1的东西)?

+0

这很好,但在我的逻辑中它不会工作,因为可以与任何员工的水平和所有家庭只有1份合同。如果我使用WHERE ID_MANAGER IS NULL,我可能找不到与管理器没有关联的合同。但我可以使用两个递归的一个是上升水平,一个是下降。 –

+0

也许吧。你想要回答什么*语义*查询?现在,您正在询问代码问题,但是编写的代码可能无法回答您打算的问题...... –

+0

@JNevill asnwer现在为我工作。但仍无法确认所有数据。 –