2009-08-30 16 views
25

SQL Server 2008で新しいHierarchyID型を使用して、小さなwikiアプリケーションのページ関係を処理したかったのです。しかし、アカウントごとのすべての主要記事/ページがルートノードになるので、複数のルートノードを持つ必要があります。複数のルートノードを持つSQL 2008階層ID

私がHierarchyIDタイプを読んだのは、1列あたり1つのルートノードしか許可されていないからです。複数のルートノードを有効にする方法はありますか?

答えて

9

はい、読んでいます.HierarchyIDを使用すると、1つのルートノードのみが許可されます。それはそうした方法であり、私が知る限り、人為的な新しい "ubber-root"を紹介するには至りません。いくつかの第1レベルの "サブルート"を持たせる以外の目的はありません。 ...

マルク・

+1

これは正しくありません。詳細は、私の[answer](http://stackoverflow.com/a/23290250/81595)を参照してください。 –

+1

@ScottMunro:あなたの答えに私のコメントを見てください。私はマークが正しいと信じています。しかし、あなたはルートノードとしてルートの子を自由に使うことができます。 – Phil

+0

@ Phil、実際には "uber-root"ノードは必要ありません。 '/ 1 /'のようなノードで階層を開始し、その上に '/'を置かなくても '/ 2 /'のような秒を持つことができます。 –

2

は、あなただけの1、「非表示」のルートを持っており、レベル1のすべての主要な記事を持つことができませんか?

29

私はいくつかのテストを行っていますが、ルートhierarchyidを持つレコードは必要ないと思われます。今

//table schema 
CREATE TABLE [Entity](
    [ID] [int] IDENTITY(1,1) NOT NULL, 
    [Name] [varchar](50) NOT NULL 
    [Hierarchy] [hierarchyid] NOT NULL, 
CONSTRAINT [PK_Entity] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
) 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

//Insert first 'root', which is technicall a child without a parent 
INSERT INTO [Entity] 
      ([Name] 
      ,[Description] 
      ,[Hierarchy]) 
    VALUES 
      ('Root A' 
      ,hierarchyid::GetRoot().GetDescendant(NULL,NULL)) 


//Create the second 'root' 
INSERT INTO [Entity] 
      ([Name] 
      ,[Hierarchy]) 
    VALUES 
      ('Root B' 
      ,hierarchyid::GetRoot().GetDescendant((select MAX(hierarchy) from entity where hierarchy.GetAncestor(1) = hierarchyid::GetRoot()),NULL)) 

たとえば、通常は1つのルートノード(レベル1)と、複数のchildenは、しかし、あなたは何のルートレコードレベル2で開始し、ちょうどレコードを持っていない、ルート・ノードをスキップすることができますあなたは、テーブルからすべての行を選択した場合は、以下を参照してください。

SELECT [ID] 
     ,[Name] 
     ,[Hierarchy], 
     [Hierarchy].ToString() 
    FROM [Entity] 

ID        名前           階層   (いいえ列名)
       ルートA         0x58                    /1/
       ルートB         0x68                    /2/

私はこれがお勧めでしょうかはわからないけど、概念的に、それはあなたと同じくらい長い間、あなたが複数のルートを持つことができますツリーの2番目のレベルをルートとして考える

+0

これは素晴らしいです、ありがとう。あなたがルートを作成するかどうかは、あなたがそれを無視するか、それをすべての階層とみなしている限り、本当に重要ではないようです。私はこれも同じ子供が複数の階層に現れることを可能にすることを期待していますが、私は子供の複製を含むと思われます。 – Davos

+1

ツリーを強制するための制約はありません。存在しない親を指している孤児レコードがないことを確認してください。詳細は私の答えを見てください。 –

9

一意のルートノードを作成するためには、テーブルPrimaryKeyを目的のアンカーレコードのHierarchyIdとしてキャストします。

ArticleID | ArticleID_Parent |階層、あなたはこのようにユニークになるためにすべての "根"を微調整することができます。

UPDATE [Article] 
SET Hierarchy=CAST('/'+CAST([ArticleID] as varchar(30))+'/' AS hierarchyid) 
WHERE [ArticleID_Parent]=0 

..特定のルートの「ブランチ」を取得する。

SELECT * FROM [Article] 
WHERE Article.Hierarchy.IsDescendantOf((SELECT Hierarchy FROM Article WHERE ArticleID=XXXX)) = 1 
+0

シッボ、それは素晴らしい仕事!ヒントをありがとう! – windchaser

6

階層内の位置を表すために使用できるhierarchyidデータ型。しかし、それは本質的に階層を強制しません。これは、hierarchyidのMSDNドキュメントの抜粋です。

階層間の値の生成と割り当ては、行間の希望の関係が値に反映されるように、アプリケーションに依存します。

このexampleは、計算された列と外部キーの組み合わせを使用してツリーを強制する方法を示しています。あなたのケースでは

CREATE TABLE Org_T3 
(
    EmployeeId hierarchyid PRIMARY KEY, 
    ParentId AS EmployeeId.GetAncestor(1) PERSISTED 
     REFERENCES Org_T3(EmployeeId), 
    LastChild hierarchyid, 
    EmployeeName nvarchar(50) 
) 
GO 

ルートレコードおそらくヌル(外部キーは、SQL Serverのnull値のために施行されていない)、またはいずれかのレコード(根の無修正hierarchyid型がなるように、あなたは計算列の式を変更します自分の両親)が返されます。

これは、ルートノードにnullのParentIdを割り当てる戦略に沿った上記の例の簡略化されたバージョンです。

create table Node 
(
    Id hierarchyid primary key, 
    ParentId AS case when Id.GetLevel() = 1 then 
        Null 
       else 
        Id.GetAncestor(1) 
       end PERSISTED REFERENCES Node(Id), 
    check (Id.GetLevel() != 0) 
) 

insert into Node (Id) values ('/1/'); 
insert into Node (Id) values ('/1/1/'); 
insert into Node (Id) values ('/'); --Fails as the roots will be at level 1. 
insert into Node (Id) values ('/2/1/'); --Fails because the parent does not exist. 

select Id.ToString(), ParentId.ToString() from Node; 

上記の有効な挿入だけが成功します。

イドParentIdは

/1/NULL

/1/1// 1/

+2

私はMarcが技術的に正しいと信じており、あなたは意味論的な意味を持っています。Marcはルートノード(/)を1つだけ持つことができます。つまり、ルートノードの子孫を "根"または "ubber-root"(Marcが呼び出した場合)と呼んで、それらを根として使用するのを止めることは何もありません。 – Phil

関連する問題