2

我正在尝试使用 CTE 遍历层次结构,它在一种情况下工作正常,但在另一种情况下却不行,这就是我卡住的地方。

给定查询;

;WITH BOMcte (ID, Code, BomName , ProductID, ProductCode, ProductName , ParentAssemblyID )
AS
(
    SELECT   b.id,
             b.code,
             b.name,
             p.id,
             p.default_code,
             p.name_template,
             b.bom_id
    FROM mrp_bom AS b
    INNER JOIN product_product p on b .product_id = p.id    
    WHERE b. bom_id IS NULL 
    and b.id = @AssemblyID 
    UNION ALL
    SELECT   b.id,
             b.code,
             b.name,
             p.id,
             p.default_code,
             p.name_template,
             b.bom_id
    FROM mrp_bom AS b
    INNER JOIN product_product p on b .product_id = p.ID    
    INNER JOIN BOMcte AS cte ON b.bom_id = cte.ID    
)
SELECT BoM.* FROM BOMcte BoM

该查询的工作方式与我预期的一样,因为 BoM 向下钻取到 bom_id 列上的子 bom。

在代码(来自 OpenERP)中,当未找到子 BoM 时,(无 bom_id)根据 product_id 搜索子产品:

sids = bom_obj.search(cr, uid, [('bom_id','=',False),('product_id','=',bom.product_id.id)])

我想知道是否有一种方法可以用来在 SQL 中完成同样的事情。一旦 CTE 不返回行,请检查 product_id 和 null bom_id。我曾考虑过另一个递归成员,但我认为这不是我想要的。

我知道我的问题可能不是很清楚,但是有什么建议吗?

SQL Fiddle 示例数据:http://sqlfiddle.com/#!3/b9052/ 1

4

2 回答 2

1

按照 HABO 的建议尝试以下操作on b.bom_id = cte.ID or ( b.bom_id is NULL and b.product_id = cte.product_id )并且您已经尝试过的原因不起作用是因为它永远不会在逻辑上终止。

但是,您确实有一个终止表达式,即在找不到孩子时执行一次。最简单的方法是添加一个 UNION 来检查以确保 BOMcte 中的一行没有孩子

WHERE NOT EXISTS (SELECT * FROM BOMcte bc WHERE b.id =  bc.PARENTASSEMBLYID)

完整的 SQL

;WITH BOMcte (ID, Code, BomName , ProductID, ProductCode, ProductName , ParentAssemblyID )
AS
(
    SELECT   b.id,
             b.code,
             b.name,
             p.id,
             p.default_code,
             p.name_template,
             b.bom_id

    FROM mrp_bom AS b
    INNER JOIN product_product p on b .product_id = p.id    
    WHERE b. bom_id IS NULL 
    and b.id = @AssemblyID 
    UNION ALL
    SELECT   b.id,
             b.code,
             b.name,
             p.id,
             p.default_code,
             p.name_template,
             b.bom_id
    FROM mrp_bom AS b
    INNER JOIN product_product p on b .product_id = p.ID    
    INNER JOIN BOMcte AS cte ON b.bom_id = cte.ID    
)
SELECT * FROM BOMcte
UNION 

SELECT   b.id,
             b.code,
             b.name,
             p.id,
             p.default_code,
             p.name_template,
             b.bom_id

    FROM mrp_bom AS b
    INNER JOIN product_product p on b.product_id = p.id 
    WHERE NOT EXISTS (SELECT * FROM BOMcte bc WHERE b.id =  bc.PARENTASSEMBLYID)

SQL 演示

注意:可以使用递增的 LEVEL 值对 CTE 中的终止表达式进行编码,如MSDN 文章中关于递归查询的那些

于 2012-10-26T21:37:56.167 回答
0

我有点不清楚您要做什么,但是对于您的最终加入,这样的事情可能会做到:

on b.bom_id = cte.ID or ( b.bom_id is NULL and b.product_id = cte.product_id )
于 2012-10-27T01:05:28.730 回答