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 にドリルダウンするため、クエリは期待どおりに機能します。

子 BoM が見つからない (bom_id がない) 場合のコード (OpenERP から) では、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 )を試してみて、すでに試してもうまくいかない理由は、論理的に終了しないためです。

ただし、子が見つからないときに一度実行するという終了式があります。最も簡単な方法は、BOMcte の行に子がないことを確認する UNION を追加することです。

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デモ

注:再帰クエリに関するMSDN の記事にあるような増分 LEVEL 値を使用して、CTE の終了式をエンコードできる場合があります。

于 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 に答える