2010-06-25 19 views
24

Dada una tabla con una columna de tipo hierarchyid, ¿cómo se escribe una consulta para devolver todas las filas que son ancestros de un nodo específico?¿Cómo se obtienen todos los antecesores de un nodo que utiliza el hierarchyid de SQL Server 2008?

Hay una función de IsDescendantOf(), lo cual es perfecto para llegar a los niños, pero no hay que corresponde IsAncestorOf() función para devolver antepasados ​​(y la ausencia de una función GetAncestors() que parece ser bastante un descuido.)

+9

no es 'child.IsDescendantOf (padre)' 'lo mismo que parent.IsAncestorOf (niño)'? – Gabe

Respuesta

24

El más utilizado enfoque sería una expresión recursiva de tabla comunes (CTE)

WITH Ancestors(Id, [Name], AncestorId) AS 
(
     SELECT 
      Id, [Name], Id.GetAncestor(1) 
     FROM 
      dbo.HierarchyTable 
     WHERE 
      Name = 'Joe Blow' -- or whatever you need to select that node 

     UNION ALL 

     SELECT 
      ht.Id, ht.[Name], ht.Id.GetAncestor(1) 
     FROM 
      dbo.HierarchyTable ht 
     INNER JOIN 
      Ancestors a ON ht.Id = a.AncestorId 
) 
SELECT *, Id.ToString() FROM Ancestors 

(adaptado de un Simon Ince blog post)

Simon Ince también propone un segundo enfoque en el que, básicamente, sólo invierte el estado - en lugar de detectar esas entradas de personas que son un antepasado de la persona objetivo, se da el cheque en torno a:

DECLARE @person hierarchyid 

SELECT @person = Id 
FROM dbo.HierachyTable 
WHERE [Name] = 'Joe Blow'; 

SELECT 
    Id, Id.ToString() AS [Path], 
    Id.GetLevel() AS [Level], 
    Id.GetAncestor(1), 
    Name 
FROM 
    dbo.HierarchyTable 
WHERE 
    @person.IsDescendantOf(Id) = 1 

Esto seleccionará todas las filas de la tabla, donde la persona objetivo que le interesa es descendiente de cualquier nivel de la jerarquía. De modo que esto encontrará los ancestros inmediatos y no inmediatos de la persona objetivo hasta la raíz.

+5

En esa publicación de blog, ¿no es esta solución CTE seguida de una más simple ("Esto funciona bien, pero ¿es la manera óptima de lograrlo? No, ¡intentémoslo de nuevo!")? – AakashM

+0

@AakashM: sí, hay una segunda opción, de hecho, no una que yo probablemente usaría, pero también funcionará por su aspecto. –

+0

Sé que esto es muy antiguo, pero escribo esto para futuros lectores: El método de "publicación de blog de Simon Ince" es casi 100 veces más lento que el método "CTE" cuando el plan de ejecución no existe. – Achilles

12

Aquí es una respuesta enrollado en un solo seleccione:

SELECT t1.Id.ToString() as Path, t1.Name 
    FROM (SELECT * FROM HierarchyTable 
     WHERE Name = 'Joe Blow') t2, 
    HierarchyTable t1 
    WHERE t2.Id.IsDescendantOf(t1.Id) = 1 
+0

El primer predicado de la cláusula where es redundante ya que un elemento primario siempre es un descendiente de sí mismo. http://msdn.microsoft.com/en-us/library/bb677203(v=sql.105).aspx – influent

2
Declare @hid hierarchyid=0x5D10 -- Child hierarchy id 

SELECT 
* 
FROM 
    dbo.TableName 
WHERE 
    @hid.IsDescendantOf(ParentHierarchyId) = 1 
+0

Incluso si tiene un índice en el hierarchyID, tendrá que evaluar IsDesendentOf para cada fila, ¿no? Creo que tengo una mejor manera (ver mi respuesta) –

0

I escribió una función de valor de tabla definida por el usuario que se expande un valor hierarchyid en sus antepasados ​​constituyentes. La salida se puede volver a unir en la columna hierarchyid para obtener esos antepasados ​​específicamente.

alter function dbo.GetAllAncestors(@h hierarchyid, @ReturnSelf bit) 
returns table 
as return 
select @h.GetAncestor(n.Number) as h 
from dbo.Numbers as n 
where n.Number <= @h.GetLevel() 
    or (@ReturnSelf = 1 and n.Number = 0) 

union all 

select @h 
where @ReturnSelf = 1 
go 

Para ir acerca de su uso:

select child.ID, parent.ID 
from dbo.yourTable as child 
cross apply dbo.GetAllAncestors(child.hid, 1) as a 
join dbo.yourTable as parent 
    on parent.hid = a.h 
+0

por favor ayúdame a resolver este problema. http://stackoverflow.com/questions/44016261/how-do-you-get-recursivelevel-using-sql-server-2012-hierarchyid – ManojKanth

Cuestiones relacionadas