2008-10-10 23 views
8

Tengo una tabla en el servidor SQL que tiene la estructura de árbol normal de Item_ID, Item_ParentID. Supongamos que quiero iterar y obtener todos los NIÑOS de un Item_ID en particular (en cualquier nivel).¿La recursión es buena en SQL Server?

Recursion parece ser un candidato intuitivo para este problema y puedo escribir una función de SQL Server para hacer esto.

¿Afectará esto el rendimiento si mi tabla tiene muchos registros? ¿Cómo evito la recursión y simplemente consulto la tabla? ¿Alguna sugerencia?

Respuesta

4

Con el nuevo MS SQL 2005 se puede utilizar la palabra clave WITH

Salida this question y en particular this answer.

Con Oracle puede usar la palabra clave CONNECT BY para generar consultas jerárquicas (syntax).

AFAIK con MySQL tendrá que usar la recursividad.

alternativa siempre se puede construir una tabla de caché para su archivo de padres y niños> relaciones

0

Quizás un poco más de detalle esté en orden.

Si tiene una relación de detalle maestro como usted lo describe, ¿no obtendrá un JOIN simple lo que necesita?

Como en:

SELECT 
    SOME_FIELDS 
FROM 
    MASTER_TABLE MT 
,CHILD_TABLE CT 
WHERE CT.PARENT_ID = MT.ITEM_ID 
1

¿Está utilizando SQL 2005?

Si es así puede usar expresiones de tabla comunes para esto. Algo a lo largo de estas líneas:

; 
with CTE (Some, Columns, ItemId, ParentId) as 
(
    select Some, Columns, ItemId, ParentId 
    from myTable 
    where ItemId = @itemID 
    union all 
    select a.Some, a.Columns, a.ItemId, a.ParentId 
    from myTable as a 
    inner join CTE as b on a.ParentId = b.ItemId 
    where a.ItemId <> b.ItemId 
) 
select * from CTE 
0

No debería ser necesario recursividad para niños - sólo se está buscando en el nivel inmediatamente inferior (es decir select * from T where ParentId = @parent) - sólo se necesita la repetición para todos los descendientes .

En SQL2005 se puede obtener con los descendientes:

with AllDescendants (ItemId, ItemText) as (
    select t.ItemId, t.ItemText 
     from [TableName] t 
    where t.ItemId = @ancestorId 
    union 
    select sub.ItemId, sub.ItemText 
     from [TableName] sub 
      inner join [TableName] tree 
      on tree.ItemId = sub.ParentItemId 
) 
+0

Creo que su problema es que quiere "En un nivel particular ". A menos que almacene el número de nivel, ¿cómo sabe qué hay en un nivel particular sin ir a raíz = nivel 1, hijos de raíz = nivel 2, hijos de niños = nivel 3, etc ... No es necesario recursividad ... .Pero puede haber múltiples padres. – Cervo

1

El problema que se enfrentará con la recursividad y el rendimiento es el número de veces que tendrá que recursivo para devolver los resultados. Cada llamada recursiva es otra llamada separada que deberá unirse en los resultados totales.

En SQL 2K5 puede utilizar una expresión de tabla común para manejar esta recursividad:

WITH Managers AS 
( 
--initialization 
SELECT EmployeeID, LastName, ReportsTo 
FROM Employees 
WHERE ReportsTo IS NULL 
UNION ALL 
--recursive execution 
SELECT e.employeeID,e.LastName, e.ReportsTo 
FROM Employees e INNER JOIN Managers m 
ON e.ReportsTo = m.employeeID 
) 
SELECT * FROM Managers 

u otra solución es aplanar la jerarquía en una otra mesa

Employee_Managers
ManagerID (PK , FK a la tabla de empleados)
EmployeeId (PK, FK en la tabla de empleados)

Todos los barcos de relación entre padres e hijos serían almacenados en esta tabla, por lo que si el Administrador de 1 gestiona Manager 2 gestiona empleado 3, la tabla se vería así:

ManagerId EmployeeId 
1   2 
1   3 
2   1 

Esto permite que la jerarquía para ser fácilmente consultada:

select * from employee_managers em 
inner join employee e on e.employeeid = em.employeeid and em.managerid = 42 

cual se devolvía a todos los empleados que tienen gestor de 42. la ventaja será mayor rendimiento, pero la baja se va a mantener la jerarquía

2

Como respuesta general, es posible hacer algunas cosas bastante sofisticada en SQL Servidor que no rmally necesita recursión, simplemente mediante el uso de un algoritmo iterativo. Logré hacer un analizador XHTML en Transact SQL que funcionó sorprendentemente bien. El pretificador de código que escribí se realizó en un procedimiento almacenado. No es elegante, es más bien como ver búfalos haciendo Ballet. pero funciona .

+0

¡Una vez escribí un reproductor de video en Transact-SQL! :-P –

+0

Puede, pero sería mucho más fácil escribir un analizador XHTML en Python/Ruby/C#/Java/Perl/LISP/etc. Y el rendimiento probablemente sería mucho mejor ... – Cervo

+0

No es honesto. ¡Esta aquí! http://www.simple-talk.com/sql/t-sql-programming/getting-html-data-workbench/ –

1

Joe Celko tiene un book (< - enlace a Amazon) específicamente en estructuras de árbol en bases de datos SQL. Si bien necesitaría recurrencia para su modelo y definitivamente habría un potencial de problemas de rendimiento allí, existen formas alternativas de modelar una estructura de árbol según lo que implique su problema específico, lo que podría evitar la recursión y brindar un mejor rendimiento.

0

No es necesario recursividad en absoluto .... Nota, he cambiado columnas a ItemID y ItemParentID para la facilidad de escribir ...

 
DECLARE @intLevel INT 
SET @intLevel = 1

INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECT ItemID, ItemParentID, @intLevel WHERE ItemParentID IS NULL

WHILE @intLevel < @TargetLevel BEGIN SET @intLevel = @intLevel + 1 INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECt ItemID, ItemParentID, @intLevel WHERE ItemParentID IN (SELECT ItemID FROM TempTable WHERE Level = @intLevel-1) -- If no rows are inserted then there are no children IF @@ROWCOUNT = 0 BREAK END

SELECt ItemID FROM TempTable WHERE Level = @TargetLevel

Cuestiones relacionadas