Pregunta

Dada una tabla de auto referencias

Item 
-------------
Id (pk)
ParentId (fk)

Con una tabla relacionada de valores asociados

ItemValue
-------------
ItemId (fk)
Amount

Y algunos datos de muestra

Item                       ItemValues 
Id      ParentId           ItemId      Amount
--------------------       ----------------------
1       null               1           10
2       1                  3           40
3       1                  3           20
4       2                  4           10
5       2                  5           30
6       null
7       6
8       7

Necesito un sproc para tomar Item.Id y devolver los hijos directos con las sumas de todos los ItemValue.Amounts para ellos, sus hijos y sus hijos hasta el final abajo del arbol

Por ejemplo, si se pasa 1 , el árbol sería 2, 3, 4, 5 los hijos directos son 2, 3 la salida sería

 ItemId    Amount
 ------------------
 2         40     (values from ItemIds 4 & 5)
 3         60     (values from ItemId 3)

¿Qué tipo de enfoques deben aplicarse para lograr este comportamiento?

Estoy considerando usar un CTE, pero me pregunto si hay un enfoque mejor / más rápido.

¿Fue útil?

Solución

Un CTE recursivo como este funcionaría, suponiendo que su jerarquía no sea demasiado profunda:

declare @ParentId int;
set @ParentId = 1;

;with 
  Recurse as (
    select 
      a.Id as DirectChildId
    , a.Id
    from Item a 
    where ParentId = @ParentId
    union all
    select
      b.DirectChildId
    , a.Id
    from Item a 
    join Recurse b on b.Id = a.ParentId
    )
select
  a.DirectChildId, sum(b.Amount) as Amount
from Recurse a
left join ItemValues b on a.Id = b.ItemId
group by
  DirectChildId;

Un método que no sea CTE requeriría alguna forma de iteración, basada en el cursor o de otra manera. Dado que es un proceso almacenado, es una posibilidad, y si hay muchos datos que revisar, probablemente se escalará mejor, siempre y cuando corte los datos adecuadamente.

Si el índice agrupado está en Id, agregue un índice no agrupado en ParentId. Como índice de cobertura, satisfará la búsqueda inicial sin una búsqueda de marcadores. El índice agrupado ayudará con la unión recursiva.

Si el índice agrupado ya está en ParentId en su lugar, agregue un índice no agrupado en Id. Juntos, serán prácticamente equivalentes a los anteriores. Para ItemValues, es posible que desee un índice en (ItemId) INCLUDE (Amount), si la tabla real es más ancha que esto.

Otros consejos

¿Podría almacenar sus datos como en el modelo de conjunto anidado? "> referencia pero las ideas son genéricas en todas las bases de datos)? Si es así, las operaciones para encontrar el valor que está buscando serían bastante simples.

¿Esto tiene que ser manejado en la base de datos? Sugeriría traer los datos necesarios a su BLL y realizar la recursión allí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top