2009-08-30 13 views
25

Quería utilizar el nuevo tipo HierarchyID en SQL Server 2008 para manejar las relaciones de página en una pequeña aplicación wiki. Sin embargo, necesitaría tener múltiples nodos raíz ya que cada artículo/página principal por cuenta sería un nodo raíz.SQL 2008 HierarchyID con múltiples nodos raíz

Según lo que he leído, el tipo HierarchyID solo permite 1 nodo raíz por columna ¿es correcto? y ¿hay alguna forma de habilitar múltiples nodos raíz?

Respuesta

9

Sí, está leyendo a la derecha: usar HierarchyID permite solo un único nodo raíz. Así es y no hay forma de evitarlo, hasta donde yo sé, salvo la introducción de una nueva "raíz virtual" artificial que no tiene otra finalidad que la de permitirle tener varias "sub-raíces" de primer nivel. ...

Marc

+1

Esto no es correcto. Ver mi [respuesta] (http://stackoverflow.com/a/23290250/81595) para más detalles. –

+1

@ScottMunro: mira mi comentario a tu respuesta. Creo que Marc está en lo cierto. Sin embargo, puede usar los elementos secundarios de root como nodos raíz – Phil

+0

@Phil. En realidad, no se requiere que tenga un nodo "uber-root". Puede comenzar una jerarquía con un nodo como '/ 1 /' y tener un segundo como '/ 2 /' sin tener que tener '/' presente sobre ellos. –

2

no puede sólo hay uno, 'no aparece' raíz y tienen todos los artículos principales en el nivel 1?

29

He estado haciendo algunas pruebas, y parece que no necesita un registro con una raíz hierarchyid.

Por ejemplo, normalmente se haría un nodo raíz (nivel 1) y múltiples Childen, pero puede omitir el nodo raíz, al no tener registros de raíz, sólo los registros que comienzan en el nivel 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)) 

Ahora si selecciona todas las filas de la tabla, que se ve:

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

ID         Nombre             Jerarquía     (No nombre de la columna)
        Root A         0x58                    /1/
        Root B         0x68                    /2/

No estoy seguro si esto se recomienda la práctica pero conceptualmente le permite tener múltiples raíces, siempre y cuando se considere el segundo nivel en el árbol como el root

+0

Esto es genial, gracias. Parece que si crea la raíz/o no no es realmente importante, siempre que la ignore o la considere 'todas las jerarquías'. Espero que esto también permita que los mismos niños aparezcan en múltiples jerarquías, aunque sospecho que eso implicará la duplicación de los niños. – Davos

+1

Parece que no tiene restricciones aquí para aplicar el árbol: asegúrese de no tener ningún registro huérfano que señale a los padres que no existen. Ver mi respuesta para más detalles. –

9

Lo que hago para crear nodos raíz únicos es simplemente convertir su tabla PrimaryKey como HierarchyId en sus registros de anclaje deseados, por ejemplo

Dada una tabla de simulación que tiene ArticleID | ArtículoID_Parent | Jerarquía, puedes modificar todas las "raíces" para que sean únicas como esta;

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

.. luego para obtener la "rama" de una raíz determinada;

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

Sichbo, ¡funcionó muy bien! ¡Gracias por el consejo! – windchaser

6

El tipo de datos hierarchyid que se puede utilizar para representar una posición en una jerarquía. Sin embargo, no obliga inherentemente a la jerarquía. Este es un extracto de la documentación de MSDN para hierarchyid.

Depende de la aplicación generar y asignar valores de hierarchyid de tal manera que la relación deseada entre las filas se refleje en los valores.

Este example muestra cómo se puede usar una combinación de una columna calculada y una clave foránea para aplicar el árbol.

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

En su caso, se modificaría la fórmula columna calculada de manera que para los registros de raíz, ya sea nulo (claves foráneas no se aplican a los valores nulos de SQL Server) o tal vez la hierarchyid no modificada del registro (serían las raíces sus propios padres) serían devueltos.

Esta es una versión simplificada del ejemplo anterior que va con la estrategia de asignar nodos raíz a ParentId nulo.

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 las inserciones válidas anteriores tienen éxito.

Id parentid

/1/NULL

/1/1// 1/

+2

Creo que Marc tiene razón en un sentido técnico y usted tiene un sentido semántico.Marc tiene razón en que puede tener solo un nodo raíz (/). Dicho esto, nada le impide llamar a los hijos "raíces" o "über-root" del nodo raíz (como Marc los llama) y usarlos como raíces (como lo hizo). – Phil

Cuestiones relacionadas