2015-10-20 140 views
0

我正在使用CTE来爆炸物料清单并需要找到所有那些具有递归组件的物料。停止递归一旦条件满足

我试图,是限制的周期(级别)的数量深,由子节点设置BOM_Level开往最大:

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 
    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 
    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 
) 

select * 
into #BOMExploded 
from BOM 
OPTION (MAXRECURSION 20) 

然而,使用这种方法,将需要后进程定位何时启动递归组件级别的循环,然后返回跟踪。

如何在给定条件下停止CTE递归查询?

ie. when top-level material_cd = component_cd for a deeper BOM_Level

回答

0

如果我理解正确的话,你并不需要停止在某一深度/水平,或者说你想停止在一定的水平,但你也需要停止的情况下,你开始反复循环材料。

在下面的递归路径的情况下: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后停止递归,以便在最终选择中捕获循环。

+0

谢谢你,这是接近正确的,因为查询的目的是简单地找到那些实际上循环的路径。所以循环开始后递归必须停止。我不知道一个设置,可以停止递归,并打印出一旦骑自行车发生了什么,如果有的话...... – Sauron

+0

有一些应该做的伎俩调整。您可以添加一个case语句,如'CASE WHEN a.path LIKE'%'+ b.material_cd +'%'THEN'CYCLE'END as CycleFlag',然后在您的最终SELECT语句的WHERE中引用该语句。 – JNevill

+0

我添加了第二个查询,它通过遍历所有递归来捕获循环,在通过一个循环后停止任何循环,然后仅显示最终选择中的循环。 – JNevill