2013-04-28 10 views
6

私は階層を持つ資産データベースで作業しています。また、資産に効果的に戻る「ReferenceAsset」テーブルもあります。参照資産は基本的にオーバーライドとして機能しますが、それはあたかも独自の新しい資産であるかのように選択されます。設定されるオーバーライドの1つは、parent_idです。階層構造を選択することに関連するSQL Server:階層化され参照されたデータを照会する

カラム:
アセット:ID(プライマリ)、
アセットリファレンスPARENT_ID:ID(プライマリ)、ASSET_ID(foreignkey->アセット)、PARENT_ID(常にアセット)
は - --EDITED 5/27 ----

サンプルReleventテーブルデータ(後に合流する):

id | asset_id | name   | parent_id | milestone | type 

    3  3  suit    null  march  shape 
    4  4  suit_banker   3   april  texture 
    5  5  tie    null  march  shape 
    6  6  tie_red    5   march  texture 
    7  7  tie_diamond   5   june  texture 
    -5  6  tie_red    4   march  texture 

id < 0(最後の行のように)は、参照されるアセットを示します。参照されるアセットには、いくつかの列がオーバーライドされています(この場合、parent_idのみが重要です)。

期待が、私は4月からすべての資産を選択した場合、私はマッチングクエリの全体の木の枝を取得するには、二次選択を行うべきであるということです。

ので、最初にクエリの一致がもたらすであろう:

4  4  suit_banker   3   april  texture 

はその後CTEの後、我々は完全な階層を取得し、私たちの結果は、この(今のところこれが働いている)

0にしてください
3  3  suit    null  march  shape 
    4  4  suit_banker   3   april  texture 
    -5  6  tie_red    4   march  texture 

とあなたが見る、IDの親:-5ありますが、何が欠けている、それが必要とされ、参照資産であり、かつ、参照資産の親:

5  5  tie    null  march  shape 
    6  6  tie_red    5   march  texture 

現在、私のソリューションはこれに対応していますが、参照の深さが1つに制限されています(実装がかなり醜いと感じています)。

---編集---- 私の主な選択機能は次のとおりです。これは実際の合併症がどこにあるかをより良く示すはずです:AssetReference。

Select A.id as id, A.id as asset_id, A.name,A.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name, B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID, 
M.name as milestoneName, A.deleted as bDeleted, 0 as reference, W.phase_name, W.status_name 
FROM Asset as A Inner Join Type as T on A.type_id = T.id 
Inner Join Batch as B on A.batch_id = B.id 
Left Join Location L on A.location_id = L.id 
Left Join Asset A2 on A.parent_id = A2.id 
Left Join AssetOwner AO on A.owner_id = AO.owner_id 
Left Join Milestone M on A.milestone_id = M.milestone_id 
Left Join Workflow as W on W.asset_id = A.id 
where A.deleted <= @showDeleted 

UNION 

Select -1*AR.id as id, AR.asset_id as asset_id, A.name, AR.parent_id as parent_id, A.subPath, T.name as typeName, A2.name as parent_name, B.name as batchName, 
L.name as locationName,AO.owner_name as ownerName, T.id as typeID, 
M.name as milestoneName, A.deleted as bDeleted, 1 as reference, NULL as phase_name, NULL as status_name 
FROM Asset as A Inner Join Type as T on A.type_id = T.id 
Inner Join Batch as B on A.batch_id = B.id 
Left Join Location L on A.location_id = L.id 
Left Join Asset A2 on AR.parent_id = A2.id 
Left Join AssetOwner AO on A.owner_id = AO.owner_id 
Left Join Milestone M on A.milestone_id = M.milestone_id 
Inner Join AssetReference AR on AR.asset_id = A.id 
where A.deleted <= @showDeleted 

私はテンポラリテーブル(#temp)をとり、階層のすべての要素を見つけるストアドプロシージャを持っています。

  1. それぞれ全体の木の枝のカンマ区切りリスト
  2. によって表される(#treeIDs)は#からのクエリに一致する資産(全体の階層構造を取得し、一時テーブルに、システム全体の階層構造を選択します。私は、採用戦略は、このましたTEMP)
  3. すべての参照資産が参照資産が常にラているので、これは今のために働くすべての参照資産

の階層構造を解析して階層構造

  • からの資産で指さ取得私が困っていると思います。私は再帰のいくつかのより良い形が必要なように感じる。ここで

    が働いている私の現在のコード、ですが、私はそれを誇りに思っていない、と私は(参照が一番下にある場合にのみ動作しますので)それは堅牢ではありません知っている:

    ステップ1。

    Select DISTINCT L.id into #RelativeIDs FROM #treeIDs 
    CROSS APPLY dbo.SplitIDs(idList) as L 
    WHERE #treeIDs.id in (Select id FROM #temp) 
    

    ステップ3.枝内のすべての参照資産を取得したクエリに一致するすべての資産の枝を選択して階層全体

    ;WITH Recursive_CTE AS (
    SELECT Cast(id as varchar(100)) as Hierarchy, parent_id, id 
    FROM #assetIDs 
    Where parent_id is Null 
    
    UNION ALL 
    
    SELECT 
    CAST(parent.Hierarchy + ',' + CAST(t.id as varchar(100)) as varchar(100)) as Hierarchy, t.parent_id, t.id 
    FROM Recursive_CTE parent 
    INNER JOIN #assetIDs t ON t.parent_id = parent.id 
    ) 
    
    
    
    Select Distinct h.id, Hierarchy as idList into #treeIDs 
    FROM (Select Hierarchy, id FROM Recursive_CTE) parent 
    CROSS APPLY dbo.SplitIDs(Hierarchy) as h 
    

    ステップ2を構築(参照資産がマイナスのID値、ひいてはID < 0の部分を持っている)

    Select asset_id INTO #REFLinks FROM #AllAssets WHERE id in 
    (Select #AllAssets.asset_id FROM #AllAssets Inner Join #RelativeIDs 
    on #AllAssets.id = #RelativeIDs.id Where #RelativeIDs.id < 0) 
    

    ステップ4は私がちょうど表示するようにしようとしたステップ3

    Select DISTINCT L.id into #extraRelativeIDs FROM #treeIDs 
    CROSS APPLY dbo.SplitIDs(idList) as L 
    WHERE 
    exists (Select #REFLinks.asset_id FROM #REFLinks WHERE #REFLinks.asset_id = #treeIDs.id) 
    and Not Exists (select id FROM #RelativeIDs Where id = #treeIDs.id) 
    

    で見つかったものの枝を取得します。関連するコード。私はより良い解決策を見つけるのを助けることができる誰にも感謝しています!

  • +0

    どのようなsqlバージョンを使用していますか? http://msdn.microsoft.com/de-de/library/bb677290.aspx – NickD

    +0

    sql server 2012、しかし私たちはちょうどそれに切り替えたので、これのほとんどは2008年に書かれました – haggercody

    答えて

    1
    --getting all of the children of a root node (could be > 1) and it would require revising the query a bit 
    
    DECLARE @AssetID int = (select AssetId from Asset where AssetID is null); 
    
    
    --algorithm is relational recursion 
    --gets the top level in hierarchy we want. The hierarchy column 
    --will show the row's place in the hierarchy from this query only 
    --not in the overall reality of the row's place in the table 
    
    WITH Hierarchy(Asset_ID, AssetID, Levelcode, Asset_hierarchy) 
    AS 
    (
    SELECT AssetID, Asset_ID, 
         1 as levelcode, CAST(Assetid as varchar(max)) as Asset_hierarchy 
    FROM Asset 
    WHERE [email protected] 
    
    UNION ALL 
    
    --joins back to the CTE to recursively retrieve the rows 
    --note that treelevel is incremented on each iteration 
    
    SELECT A.Parent_ID, B.AssetID, 
         Levelcode + 1 as LevelCode, 
         A.assetID + '\' + cast(A.Asset_id as varchar(20)) as Asset_Hierarchy 
    FROM Asset AS a 
          INNER JOIN dbo.Batch AS Hierarchy 
          --use to get children, since the parentId of the child will be set the value 
          --of the current row 
          on a.assetId= b.assetID 
    --use to get parents, since the parent of the Asset_Hierarchy row will be the asset, 
          --not the parent. 
          on Asset.AssetId= Asset_Hierarchy.parentID 
    
    
    SELECT a.Assetid,a.name, 
         Asset_Hierarchy.LevelCode, Asset_Hierarchy.hierarchy 
    FROM  Asset AS a 
         INNER JOIN Asset_Hierarchy 
           ON A.AssetID= Asset_Hierarchy.AssetID 
    ORDER BY Hierarchy ; 
    --return results from the CTE, joining to the Asset data to get the asset name 
    ---that is the structure you will want. I would need a little more clarification of your table structure 
    
    +0

    うわー。ブリリアント。ありがとうございました! – haggercody

    0

    基本的なテーブル構造を理解するのに役立ちます。あなたの環境に応じて動作するべき2つのアプローチがあります:SQLはXMLを理解するので、SQL構造をXMLにするか、一意の主キーIDと親IDを持つ各行項目を持つ単一のテーブルを持ちます。 idは親のfkです。ノードのデータは標準列に過ぎません。計算された列に電力を供給する関数または関数を使用して、各ノードの入れ子の度合いを決定することができます。ノードには親が1つしかないという制限があります。

    +0

    これを見ていただきありがとうございます。
    私はテーブル構造をよりよく示す選択機能でOPを更新しました。問題は本当にAssetReferenceテーブルの周りです。 、私は(これまでの罰金)[BallCap]のための全体の木の枝を選択 をしかし、私は中AssetReferenceに遭遇 - 私は[BallCap]取得: は は、私は、バッチ帽子で資産を選択し考えてみましょう:私は、特定の状況を説明してみましょうツリー 参照先の元資産 を選択する必要があります。次に、この資産のツリー全体が必要です – haggercody

    +0

    ノード用のブランチセットがあり、そのブランチの1つにオンになっているノードまったく違う木? –

    +0

    はい、ブランチのノードは、別のツリーブランチにある可能性のある別のノードを「参照」できます。この '参照'は別のテーブル(AssetReference)からのものです。私はここで設計戒めを破ったのですか? – haggercody

    関連する問題