2012-10-26 20 views
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上向下鑽取子boms。

在代碼中(從OpenERP的)當孩子沒有找到物料清單(無bom_id)子產品中搜索基礎上的product_id:

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

我想知道如果有一個方法,我可以用來在SQL中完成同樣的事情。一旦CTE不返回行,請檢查product_id和空bom_id。我曾想過另一個遞歸成員,但我不認爲這就是我正在尋找的。

我知道我的問題可能不是很清楚,但是,有什麼建議嗎?

這裏SQL小提琴示例數據:http://sqlfiddle.com/#!3/b9052/1

回答

1

之所以試圖爲哈勃建議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 DEMO

注:這是可能的在遞歸查詢中使用類似於MSDN article中遞增的遞增LEVEL值對CTE中的終止表達進行編碼

+0

不完全;它會返回一個重複的子行。 – ehcanadian

+0

我懷疑我錯了'WHERE NOT EXISTS(SELECT * FROM mrp_bom mb WHERE mb.bom_id = b.ID)'你能創建一些樣本數據嗎? [SQL小提琴](http://sqlfiddle.com/)也不錯。 –

+0

這對你有幫助嗎?我以前沒有使用SQL Fiddle。 http://sqlfiddle.com/#!3/b9052/1(編輯的網址) – ehcanadian

0

我是一個有點ü n清楚你想做什麼,但是像你這樣的最後加入可能會這樣做:

on b.bom_id = cte.ID or (b.bom_id is NULL and b.product_id = cte.product_id) 
+0

這正是我想要做的,我試着添加你提到的條件,但是我達到了maxrecursion限制。 (它在產品ID上循環) – ehcanadian

+0

可以使用[MAXRECURSION](http://msdn.microsoft.com/en-us/library/ms181714.aspx)查詢提示來增加或刪除遞歸限制。你確定它沒有卡在一個循環中,例如在BoM和產品之間來回移動? – HABO