sets functions sql-server hierarchyid

sql-server - sets - group functions sql server



ID de jerarquía SQL 2008 con múltiples nodos raíz (6)

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

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


¿No puedes tener una raíz "no mostrada" y tener todos los artículos principales en el nivel 1?


El tipo de datos hierarchyid que se puede usar para representar una posición en una jerarquía. Sin embargo, no impone inherentemente 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 jerarquía 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 externa para imponer 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, modificaría la fórmula de la columna calculada para que, para los registros raíz, sea Nulo (las claves foráneas no se aplican para valores Nulos en SQL Server) o tal vez se devuelva el hierarchyid no modificado del registro (las raíces serían sus propios padres) .

Esta es una versión simplificada del ejemplo anterior que acompaña a 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 de arriba tienen éxito.

Id ParentId

/ 1 / NULL

/ 1/1 / / 1 /


He estado haciendo algunas pruebas, y parece que no necesita un registro con una jerarquía jerárquica.

Por ejemplo, normalmente lo haría con un nodo raíz (nivel 1) y varios hijos, pero puede omitir el nodo raíz, sin tener registros de raíz, solo 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, verá:

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

Jerarquía de nombres de ID (Sin nombre de columna)
1 Raíz A 0x58 / 1 /
2 Raíz B 0x68 / 2 /

No estoy seguro si esto sería una práctica recomendada, pero conceptualmente le permite tener múltiples raíces, siempre y cuando considere el segundo nivel en el árbol como la raíz.


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

Dada una mesa de simulación que tiene ArticleID | ArticleID_Parent | Jerarquía, puedes modificar todas las "raíces" para convertirte en único como este;

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 particular;

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


Sí, está leyendo correctamente: el uso de HierarchyID permite solo un único nodo raíz. Así es y no hay forma de evitarlo, por lo que sé, a menos que introduzca una nueva "über-root" artificial que no tiene otro propósito que permitirle tener varias "subraíz" de primer nivel. ...

Bagazo

Actualización: como Greg (@ Greg0) ha señalado, esta respuesta en realidad no es correcta, vea su respuesta para obtener más detalles.


Sí puedes tener múltiples raíces.

No hay restricción de motor de base de datos en múltiples raíces. Pero por supuesto necesitas un discriminador al seleccionar. Considere lo siguiente que usa ''División'' como discriminador:

CREATE TABLE [EmployeeOrg]( [OrgNode] [hierarchyid] NOT NULL, [OrgLevel] AS ([OrgNode].[GetLevel]()), [EmployeeID] [int] NOT NULL, [Title] [varchar](20) NULL, [Division] [int] not null ) ON [PRIMARY] GO Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/'', 1, ''Partner A'', 1 ); Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/1/'', 2, ''Part A Legal'', 1 ); Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/1/1/'', 3, ''Part A Legal Asst'', 1 ); Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/'', 4, ''Partner B'', 2 ); Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/1/'', 5, ''Partner B Legal'', 2 ); Insert into EmployeeOrg (OrgNode, EmployeeID, Title, Division) values (''/1/1/'', 6, ''Partner B Legal Asst'', 2 ); SELECT * FROM EmployeeOrg WHERE OrgNode.IsDescendantOf(''/'') = 1 and Division = 1 SELECT * FROM EmployeeOrg WHERE OrgNode.IsDescendantOf(''/'') = 1 and Division = 2

Esto devuelve las dos jerarquías diferentes como se esperaba.