如果我理解正确的话,你并不需要停止在某一深度/水平,或者说你想停止在一定的水平,但你也需要停止的情况下,你开始反复循环材料。
在下面的递归路径的情况下:mat_1
- >mat_2
- >mat_3
- >mat_1
,你想阻止,去年mat_1
再次开始骑自行车mat_2
等之前。
如果这是正确的,那么你最好的选择是一个Path
字段添加到您的递归查询跟踪每一个找到任期下移的递归路径:
exec pr_sys_drop_object '#BOMExploded'
;with BOM
as
(
select
Prod_Plant_CD
, Demand_Plant_CD
, material_cd
, component_cd
, component_quantity
, component_quantity AS Calculated_Component_Quantity
, BOM_Level
, Demand_Quantity
, CONVERT(float,1) AS Produced_Ratio
, Material_CD AS Demand_Material_CD
, CAST(material_cd AS VARCHAR(100)) AS Path
from #firstLevel a
UNION ALL
SELECT
b.Plant_CD as 'Prod_Plant_CD'
, a.Demand_Plant_CD
, b.Material_CD
, b.Component_CD
, b.component_quantity
, b.component_quantity
, a.BOM_Level + 1
, a.Demand_Quantity
, a.Produced_Ratio * a.Component_Quantity -- Produced Quantity for the current level = Produced Quantity (level -1) * Component_Quantity (level -1)
, a.Demand_Material_CD
, a.Path + '|' + b.material_cd
FROM BOM a
inner join #BOM_ProdVersion_Priority b
on a.component_cd = b.material_cd
inner join #base_routes c
on a.Demand_Plant_CD = c.Recipient_Plant_CD
and b.Plant_CD = c.Source_Plant_CD
and c.Material_CD = b.Material_CD -- Need to have material_cd to link
where b.Material_CD != b.Component_CD
and b.Component_Quantity > 0
and BOM_Level < 5 -- Give the max number of levels deep we are allowed to cyncle to
and a.path NOT LIKE '%' + b.material_cd + '%'
)
select *
into #BOMExploded
from BOM
OPTION (MAXRECURSION 20)
现在你有一个path
那是由管道分隔的,您可以测试当前的material_cd
以查看它是否已在path
中。如果是这样,那么你结束递归的那一段,以防止骑车。
更新包括一个版本,我们捕捉material_cd周期,只报告那些在递归的终点:
exec pr_sys_drop_object '#BOMExploded'
;with BOM
as
(
select
Prod_Plant_CD
, Demand_Plant_CD
, material_cd
, component_cd
, component_quantity
, component_quantity AS Calculated_Component_Quantity
, BOM_Level
, Demand_Quantity
, CONVERT(float,1) AS Produced_Ratio
, Material_CD AS Demand_Material_CD
, CAST(material_cd AS VARCHAR(100)) AS Path
, CAST(NULL AS CHAR(5)) as Cycle_Flag
, 0 as Cycle_Depth
from #firstLevel a
UNION ALL
SELECT
b.Plant_CD as 'Prod_Plant_CD'
, a.Demand_Plant_CD
, b.Material_CD
, b.Component_CD
, b.component_quantity
, b.component_quantity
, a.BOM_Level + 1
, a.Demand_Quantity
, a.Produced_Ratio * a.Component_Quantity -- Produced Quantity for the current level = Produced Quantity (level -1) * Component_Quantity (level -1)
, a.Demand_Material_CD
, a.Path + '|' + b.material_cd
, CASE WHEN a.path NOT LIKE '%' + b.material_cd + '%' then 'Cycle' END AS Cycle_Flag,
, CASE WHEN a.path NOT LIKE '%' + b.material_cd + '%' then a.Cycle_Depth + 1 END as Cycle_Depth
FROM BOM a
inner join #BOM_ProdVersion_Priority b
on a.component_cd = b.material_cd
inner join #base_routes c
on a.Demand_Plant_CD = c.Recipient_Plant_CD
and b.Plant_CD = c.Source_Plant_CD
and c.Material_CD = b.Material_CD -- Need to have material_cd to link
where b.Material_CD != b.Component_CD
and b.Component_Quantity > 0
and a.cycle_depth < 2 --stop the query if we start cycling, but only after we capture at least one full cycle
)
select *
into #BOMExploded
from BOM
WHERE cycle_flag IS NOT NULL
OPTION (MAXRECURSION 20)
这将捕获cycle_depth这是衡量如何深入到一个循环的计数器我们得到了。我们在达到1的cycle_depth后停止递归,以便在最终选择中捕获循环。
谢谢你,这是接近正确的,因为查询的目的是简单地找到那些实际上循环的路径。所以循环开始后递归必须停止。我不知道一个设置,可以停止递归,并打印出一旦骑自行车发生了什么,如果有的话...... – Sauron
有一些应该做的伎俩调整。您可以添加一个case语句,如'CASE WHEN a.path LIKE'%'+ b.material_cd +'%'THEN'CYCLE'END as CycleFlag',然后在您的最终SELECT语句的WHERE中引用该语句。 – JNevill
我添加了第二个查询,它通过遍历所有递归来捕获循环,在通过一个循环后停止任何循环,然后仅显示最终选择中的循环。 – JNevill