2012-04-29 40 views
9

Tengo una tabla Person que tiene 3 columnas: Id, Name, ParentId donde ParentId es Id de la fila primaria.Consulta de datos de estructura de árbol en SQL Server

Actualmente, para mostrar todo el árbol, debería recorrer todos los elementos secundarios hasta que no haya más elementos secundarios. No parece demasiado eficiente.

¿Existe una manera mejor y más eficiente de consultar estos datos?

Además, ¿hay una mejor manera de representar esta estructura arborescente en una base de datos de SQL Server? ¿Un diseño alternativo para mi mesa/base de datos?

+0

Consulte http://stackoverflow.com/questions/935098/database-structure-for-tree-data-structure para obtener una pregunta similar con respuestas. – JeremyDWill

+1

Vea la baraja de diapositivas de Bill Karwin [SQL Antipatterns back] (http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back) - describe varios antipatrones - entre ellos el "árbol ingenuo" que tiene - y ofrece posibles soluciones para ello. También tiene un gran libro con el mismo nombre [SQL Antipatterns] (http://pragprog.com/book/bksqla/sql-antipatterns) - ¡muy recomendado! –

Respuesta

17

No creo que haya nada de malo en el diseño, suponiendo que tenga un nivel limitado de relaciones entre padres e hijos. Aquí está un ejemplo rápido de la recuperación de la relación mediante un CTE recursiva:

USE tempdb; 
GO 

CREATE TABLE dbo.tree 
(
    ID INT PRIMARY KEY, 
    name VARCHAR(32), 
    ParentID INT FOREIGN KEY REFERENCES dbo.tree(ID) 
); 

INSERT dbo.tree SELECT 1, 'grandpa', NULL 
UNION ALL SELECT 2, 'dad', 1 
UNION ALL SELECT 3, 'me', 2 
UNION ALL SELECT 4, 'mom', 1 
UNION ALL SELECT 5, 'grandma', NULL; 

;WITH x AS 
(
    -- anchor: 
    SELECT ID, name, ParentID, [level] = 0 
    FROM dbo.tree WHERE ParentID IS NULL 
    UNION ALL 
    -- recursive: 
    SELECT t.ID, t.name, t.ParentID, [level] = x.[level] + 1 
    FROM x INNER JOIN dbo.tree AS t 
    ON t.ParentID = x.ID 
) 
SELECT ID, name, ParentID, [level] FROM x 
ORDER BY [level] 
OPTION (MAXRECURSION 32); 
GO 

No se olvide de limpiar:

DROP TABLE dbo.tree; 

This might be a useful article. Una alternativa es hierarchyid pero me resulta demasiado complejo para la mayoría de los escenarios .

+1

No es relevante para el tema, pero ¿no son tus hermanos "mamá" y "papá", de acuerdo con la estructura de tu árbol? :) Quiero decir un significado diario en vivo, como si tuvieran el mismo padre. Oh, no importa –

+0

@Varvara Sí, claro. –

4

La respuesta de Aaron Bertrands es muy buena para el caso general. Si solo necesita mostrar todo el árbol a la vez, puede consultar toda la tabla y realizar la creación de árboles en la memoria. Es probable que esto sea más conveniente y flexible. El rendimiento también será ligeramente mejor (toda la tabla debe descargarse de todos modos y C# es más rápido para tales cálculos que SQL Server).

Si solo necesita una parte del árbol, no se recomienda este método porque estaría descargando más datos de los necesarios.

Cuestiones relacionadas