2009-08-30 10 views
25

Volevo utilizzare il nuovo tipo HierarchyID in SQL Server 2008 per gestire le relazioni di pagina in una piccola applicazione wiki. Tuttavia, sarebbe necessario disporre di più nodi radice poiché ogni articolo/pagina principale per account sarebbe un nodo radice.HierarchyID di SQL 2008 con più nodi di radice

Da quello che ho letto il tipo HierarchyID consente solo 1 nodo radice per colonna è corretto? e c'è un modo per abilitare più nodi radice?

risposta

9

Sì, stai leggendo bene - l'utilizzo di HierarchyID consente solo un singolo nodo radice. Questo è il modo in cui è e non c'è modo di aggirarlo, per quanto ne so, a meno di introdurre una "nuova radice" artificiale che non ha altro scopo se non quello di permetterti di avere diverse "sotto-radici" di primo livello. ...

Marc

+1

Questo non è corretto. Vedi la mia [risposta] (http://stackoverflow.com/a/23290250/81595) per i dettagli. –

+1

@ScottMunro: vedere il mio commento per la risposta. Credo che Marc abbia ragione. Tuttavia, sei libero di utilizzare i figli di root come root-node – Phil

+0

@Phil, in realtà non è necessario avere un nodo "uber-root". Puoi iniziare una gerarchia con un nodo come '/ 1 /' e avere un secondo come '/ 2 /' senza dover avere '/' presente sopra di loro. –

2

non puoi semplicemente avere uno, 'non-visualizzati' root ed avere tutti gli articoli principali a livello 1?

29

Ho eseguito alcuni test e sembra che non sia necessario un record con una gerarchia di root.

Per esempio, normalmente si avrebbe un nodo radice (livello 1) e più infantile, ma si può saltare il nodo principale, non avendo record di root, solo i record che iniziano a livello 2:

//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)) 

Ora se si seleziona tutte le righe della tabella, si vede:

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

ID         Nome             Gerarchia     (No nome della colonna)
        Root Un         0x58                    /1/
        Root B         0x68                    /2/

Non sono sicuro se questo sarebbe raccomandato pratica, ma concettualmente si permette di avere radici multiple, fino a quando si considerare il 2 ° livello nell'albero come radice

+0

Questo è grandioso, grazie. Sembra che la creazione della radice/o non sia veramente importante, a patto di non tenerne conto, o di considerarla "tutte le gerarchie". Spero che questo consenta anche agli stessi bambini di apparire in più gerarchie, anche se sospetto che ciò comporti la duplicazione dei bambini. – Davos

+1

Qui non sembra che vi siano dei vincoli per imporre l'albero - assicurati di non avere alcun registro orfano che punti a genitori che non esistono. Vedi la mia risposta per maggiori dettagli. –

9

Cosa faccio per rendere i nodi radice univoci è appena lanciato la tabella PrimaryKey come HierarchyId sui record di ancoraggio desiderati, ad es.

Dato una tabella di simulazione con ArticleID | ArticoloID_Parent | Gerarchia, puoi modificare tutte le "radici" per diventare uniche come questa;

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

.. quindi ottenere il "ramo" di una radice specifica;

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

Sichbo, che ha funzionato alla grande! Grazie per il consiglio! – windchaser

6

Il tipo di dati gerarchici che può essere utilizzato per rappresentare una posizione in una gerarchia. Tuttavia non applica forzatamente la gerarchia. Questo è un estratto dalla documentazione MSDN per hierarchyid.

Spetta all'applicazione generare e assegnare valori gerarchici in modo tale che la relazione desiderata tra le righe sia riflessa nei valori.

Questo example mostra come una combinazione di una colonna calcolata e una chiave esterna può essere utilizzata per imporre l'albero.

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

Nel tuo caso, si dovrebbe modificare la formula colonna calcolata in modo che per i record di root sia Null (chiavi esterne non vengono applicate per i valori Null in SQL Server) o forse il hierarchyid non modificata del record (radici sarebbero i propri genitori) sarebbero stati restituiti.

Questa è una versione semplificata dell'esempio precedente che accompagna la strategia dell'assegnazione di nodi radice a un ParentId null.

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; 

Solo gli inserimenti validi da sopra hanno esito positivo.

Id ParentId

/1/NULL

/1/1// 1/

+2

Credo che Marc abbia ragione in senso tecnico e tu sei in senso semantico.Marc ha ragione nel fatto che puoi avere un solo nodo radice (/). Detto questo, nulla ti impedisce di chiamare i "root" dei figli del root root o "über-root" (come li chiama Marc) e usare quelli come root (come hai fatto tu). – Phil

Problemi correlati