Pergunta

Dada uma tabela de auto referenciação

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

Com uma tabela relacionada de valores associados

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

E alguns dados de exemplo

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

Eu preciso de um sproc para tomar Item.Id e retornar os filhos diretos com somas de todos ItemValue.Amounts para eles, seus filhos e seus filhos todo o caminho até a árvore.

Por exemplo, se 1 é passado, a árvore seria 2, 3, 4, 5 os filhos diretos são 2, 3 a saída seria

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

Que tipo de abordagens deve ser aplicado para fazer atingir esse comportamento?

Eu estou pensando em usar uma CTE, mas estou querendo saber se há uma melhor abordagem / mais rápido.

Foi útil?

Solução

A recursiva CTE como isso iria funcionar, assumindo sua hierarquia não ir muito fundo:

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;

Um método não-CTE exigiria algum tipo de iteração,-cursor com base ou de outra forma. Desde que é um proc armazenados, é uma possibilidade, e se há um conjunto de dados muito a recurse através, ele provavelmente iria escalar melhor, contanto que você dividir os dados de forma adequada.

Se o índice de cluster está em Id, adicionar um índice não agrupado em ParentId. Como um índice de cobertura, que irá satisfazer a inicial procurar w / out uma pesquisa de indicador. O índice agrupado, então, ajuda com a recursiva participar.

Se o índice de cluster já está em ParentId em vez disso, adicionar um índice não agrupado em Id. Juntos, eles irão ser virtualmente equivalente ao anterior. Para ItemValues, você pode querer um índice em (ItemId) incluem (Valor), se a tabela real é maior do que isso.

Outras dicas

Você poderia armazenar seus dados, como no modelo de conjunto aninhado (aqui é um MySQL referência, mas as idéias são genéricos entre bancos de dados)? Se sim, então as operações para encontrar o valor que você está procurando seria bastante simples.

Será que isso tem que ser tratado no banco de dados? Gostaria de sugerir trazendo os dados necessários para a sua BLL e executar a recursão lá.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top