2016-05-25 25 views
0

ツリービューで表現されたリレーショナルデータベースに階層構造が格納されています。 各ノードはそのプロパティのためのさまざまなフィールドを持ち、その親をIDで知っています。 これは親子関係モデルです。SQL:nレベルの階層構造

ノードに子がある場合、ノード名の前に[+]が表示されます。 [+]をクリックすると、ノードを展開してノードの子を見ることができます。 最下位レベルまで子ノードがある場合、子ノード自体に[+]があります。

簡略化された例のツリービューは、次のようになります

  [+] A Land 
         [+] A.1 Car 
            A.1.A Motor 
            A.1.B Wheels 
      [+] B Sea 
          B.1 Sailing ship 
         [+] B.2 Motorboat 
            B.2.A Motor 
      [+] C Air 
         [+] C.1 Plane 
            C.1.A Turbine 
            C.2.B Wheels              

これは、例えば、様々なノードのプロパティ上の1つまたは複数のフィルタを設定することが可能です名前が「モーター」である子孫を持つすべてのノードを表示します。私はレベルの限られた数とノードの少量を持っているように、この構造は、(平凡なパフォーマンスで)私のニーズを満たす

  [+] A Land 
          [+] A.1 Car 
             A.1.A Motor           
      [+] B Sea         
          [+] B.2 Motorboat 
             B.2.A Motor 

: ツリービューは次のようになります。

ここで、ツリービューをnレベルの深さに拡張します。

ネストされたセットモデルがあり、フィルタリングしない限りパフォーマンスは優れています。ネストされたセットは、わかっている限り、フィルタリングをサポートしていないからです。また、パスモデル(SQL-Servers hierarchyid-datatype)も試しましたが、レベルが高い場合はフィルタリングが遅くなります。


私たちのパスモデルのアプローチ: あなたはhierarchyid型・データ型の列のパスを持っているtbale PMTableの各レベルにおけるノードの多い、と20個のレベルを持っている想像してみてください。次に、少なくとも1つの子孫(直接的な子孫でなくてはならず、descandantがすべての可能なレベルを持つことができなければならない)を持つトップレベルのノードをすべてクエリする(TreeViewを初期化する)ことは望ましくありません。 LIKE '%motor%' AND type = 3、名前とタイプは同じパスモデル表の列です)。また、クエリの簡素化のためにノードのゼロベースのレベルを保存しました。

クエリは次のようになります。

SELECT id, name 
FROM PMTable WHERE level = 0 
AND Path IN 
(
    SELECT Path WHERE Path.GetAncestor(Path.GetLevel() - 1) 
    FROM PMTable 
    WHERE name LIKE '%motor%' AND type = 3 
) 
ORDER BY name 

このクエリは、おそらく平凡なパフォーマンスですが、あなたが見ることができるよう、また、トップレベルのクエリで使用すると、テーブルからすべてのノードを照会している高価なサブクエリを、持っていますその基準に一致する。

しかし、小さな[+]をクリックして1つの最上位ノードを展開すると、2番目のレベルのノードをすべて照会し、そのノードを祖先とし、そのフィルタ基準一致する)。ノード自体がそのフィルタ条件(タイプ3で名前に 'motor'を含む)と一致する場合、その子孫のすべてを表示する必要があります。

これらのクエリは、この例ではパフォーマンスが低下しています。


他にも好きなモデルがありますか、これを改善するためのアイデアはありますか?

ありがとうございます!

+0

ネストセットモデルでフィルタリングできない理由の例がありますか?子孫によるフィルタリングは、実際にはそのモデルでは非常に簡単です。 –

+0

私が知る限り、ノードに子孫があるかどうかを簡単に確認できます。 しかし、ノードにはいくつかのフィルタ条件に一致する偶然があるかどうかをチェックする必要があります。ネストされたセットモデルの左と右の値がデカンダントを含むかどうかについてのフィードバックを与える限り、私はいくつかの行をフィルタリングすると変更されませんが、方法はありません。私は正しい? –

+0

もちろん、ネストされたセットとフィルタリングを使用できます。子孫を持つすべてのノードを選択します(つまり、ノードの左右に子孫のある/左にあるノードを意味する)か、フィルタの条件を満たすノードを選択します。 'select * from node where exists(select *あなたのノードのフィルタクリティアとnode.left <= n.leftおよびnode.right> = n.right)の '' n ''というノードから ' – Solarflare

答えて

0

SQL Serverの2005年以来、T-SQL開発者はあなたが言及SQLチュートリアルをチェックした場合、あなたはサンプルデータを検索し、最後のスクリーンショット

でCTEクエリおよび階層のレベルをサンプリングします recursive queries with CTE structures for hierarchy data

を実行することができます再帰CTEは、CTEのアンカーSelectステートメントに1としてhierarchの初期レベルを追加し、再帰部分に1でこれを増やすことで、SQL Serverの

WITH cte AS (
    {Anchor_Query} 
    UNION ALL 
    {Recursive part joining to cte} 
) 
SELECT * FROM cte 

に次のように、あなたは意志が形成される

最終的にあなたの結果のデータセット

内のすべての階層レベルで終わる私は2 20年以上前から私の階層の範囲のキーを使用してきたサンプルSQLチュートリアル

1

を確認してください。私たちは、報告、処理、および/または選択基準に使用されている大規模で多数の代替階層を持っていました。私はまた、迅速なナビゲーションとユーティリティのための関数のライブラリを作成しました。

以下は簡単なサンプルです。範囲キーを手動で作成したことを覚えておいてください。通常はプログラムによって作成/更新されます。また、私は通常、アトリビューション中のレベル別に実際のシーケンスを制御するためのプレゼンテーションシーケンス番号を持っています。

本当の美しさは、再帰的クエリを使用せずに可変深度データを簡単に集約できることです。

私はこのテクニックを説明したかったので、下のクエリにはすべてのヘルパーが足りません。

Declare @OH table (OH_R1 int,OH_R2 int,OH_Lvl int,OH_Nr int,OH_Pt int,OH_Title varchar(100)) 
Insert into @OH Select 0,12,1,9,0,'Total' 
Insert into @OH Select 1,4,2,100,9,'Land' 
Insert into @OH Select 2,4,3,200,100,'Car' 
Insert into @OH Select 3,3,4,300,200,'Motor' 
Insert into @OH Select 4,4,4,400,200,'Wheels' 
Insert into @OH Select 5,8,2,500,9,'Sea' 
Insert into @OH Select 6,6,3,600,500,'Sailing Ship' 
Insert into @OH Select 7,8,3,625,500,'Motor Boat' 
Insert into @OH Select 8,8,4,650,625,'Motor' 
Insert into @OH Select 9,12,2,800,9,'Air' 
Insert into @OH Select 10,12,3,825,800,'Plane' 
Insert into @OH Select 11,11,4,550,825,'Turbine' 
Insert into @OH Select 12,12,4,550,825,'Wheele' 

-- Show Nested/Filtered Hierarchy 
Select A.* 
     ,Nested=Replicate(' ',OH_Lvl-1)+OH_Title 
     ,Hits=sum(hits) 
From @OH A 
Join (Select OH_R1,Hits=1 from @OH where OH_Title like '%motor%' and OH_Lvl=4) B on (B.OH_R1 between A.OH_R1 and A.OH_R2) 
Group by A.OH_R1,A.OH_R2,A.OH_Lvl,A.OH_Nr,A.OH_Pt,A.OH_Title 
Order by OH_R1 


-- Show Actual Hierarchy 
Select * from @OH Order by OH_R1 

戻り

OH_R1 OH_R2 OH_Lvl OH_Nr OH_Pt OH_Title Nested    Hits 
0  12  1  9  0  Total  Total    2 
1  4  2  100  9  Land   Land    1 
2  4  3  200  100  Car    Car    1 
3  3  4  300  200  Motor    Motor   1 
5  8  2  500  9  Sea   Sea    1 
7  8  3  625  500  Motor Boat  Motor Boat 1 
8  8  4  650  625  Motor    Motor  1 
0

ネストされたセットのモデルを使用して、名前の子孫を持つすべての木を見つける「モーター」は非常に単純でなければなりません:

SELECT 
    P.name -- Or whatever other columns you need 
FROM 
    My_Tree D 
INNER JOIN My_Tree P ON P.lft <= D.lft AND P.rgt >= D.rgt 
WHERE 
    D.name = 'Motor' 

あなたがしたい場合はそのノードの子孫も含めて(つまり、そのメンバーがその名前を持つ完全なツリー)、子ノードを取得するためにORステートメントを簡単に追加することができます。

0

ご協力いただきありがとうございます。本当に助けになりました。 Path-Modelと再帰的なCTEの組み合わせを思い出しました。テーブルに親IDを追加して追加のパフォーマンス向上を追加しました。

関連する問題