2012-04-29 13 views
9

私はテーブルId, Name, ParentIdの3列のテーブルPersonを持っています。ここでParentIdは親の行のIdです。SQL Serverのツリー構造のデータクエリ

現在、ツリー全体を表示するには、子要素がなくなるまですべての子要素をループする必要があります。あまりにも効率的ではないようです。

このデータをより正確かつ効率的にクエリする方法はありますか?

また、SQL Serverデータベースでこのツリー構造のように表現する方が良いでしょうか?私のテーブル/データベースの別のデザインですか?

+0

回答と同様の質問についてはhttp://stackoverflow.com/questions/935098/database-structure-for-tree-data-structureを参照してください。 – JeremyDWill

+1

Bill Karwinの[SQL Antipatterns strike back](http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back)のスライドデッキを参照してください - 彼はいくつかの反パターンについて説明しています - あなたの持っている "ナイーブツリー"可能な解決策を提供します。彼は同じ名前の素晴らしい本[SQL Antipatterns](http://pragprog.com/book/bksqla/sql-antipatterns)もお勧めします。 –

答えて

17

親子関係が限られていると想定して、デザインに何か問題はないとは思わない。ここでは、再帰CTEを使用して関係を取得する簡単な例です:

USE tempdb; 
GO 

CREATE TABLE dbo.tree 
(
    ID INT PRIMARY KEY, 
    name VARCHAR(32), 
    ParentID INT FOREIGN KEY REFERENCES dbo.tree(ID) 
); 

INSERT dbo.tree SELECT 1, 'grandpa', NULL 
UNION ALL SELECT 2, 'dad', 1 
UNION ALL SELECT 3, 'me', 2 
UNION ALL SELECT 4, 'mom', 1 
UNION ALL SELECT 5, 'grandma', NULL; 

;WITH x AS 
(
    -- anchor: 
    SELECT ID, name, ParentID, [level] = 0 
    FROM dbo.tree WHERE ParentID IS NULL 
    UNION ALL 
    -- recursive: 
    SELECT t.ID, t.name, t.ParentID, [level] = x.[level] + 1 
    FROM x INNER JOIN dbo.tree AS t 
    ON t.ParentID = x.ID 
) 
SELECT ID, name, ParentID, [level] FROM x 
ORDER BY [level] 
OPTION (MAXRECURSION 32); 
GO 

をクリーンアップすることを忘れないでください:

DROP TABLE dbo.tree; 

This might be a useful article.代替はhierarchyidですが、私は、ほとんどのシナリオで、それは非常に複雑見つけます。

+1

あなたのツリーの構造によれば、トピックには関係ありませんが、あなたの「お母さん」と「お父さん」の兄弟はありませんか? :)彼らは同じ父親を持っているように、私は毎日のライブの意味を意味します。ああ、決して気にしないでください –

+0

@Varvaraええ、確かに。 –

4

一般的なケースでは、Aaron Bertrandsの回答が非常に良いです。一度にツリー全体を表示する必要がある場合は、テーブル全体をクエリし、メモリ内のツリー構築を実行するだけで済みます。これは、より便利で柔軟性が高い可能性があります。パフォーマンスも若干向上します(テーブル全体をダウンロードする必要があり、C#はSQL Serverよりも高速です)。

ツリーの一部だけが必要な場合は、必要以上に多くのデータをダウンロードするため、この方法はお勧めしません。

関連する問題