web-dev-qa-db-fra.com

CTE pour obtenir tous les enfants (descendants) d'un parent

J'ai ce problème qui me donne mal à la tête ...

Disons, j'ai une table avec quelques milliers de lignes et la structure de la table se compose d'une relation parent -> enfant.

Les relations peuvent aller jusqu'à 6 niveaux. Voici un exemple de la structure du tableau:

ProductId | ParentId | Levels
1174           0        1174
311           1174      311, 1174
1186          311       1186, 311, 1174
448           1186      448, 1186, 311, 1174
3365          448       3365, 448, 1186, 311, 1174

Nous avons un processus qui parcourt toute la table pour obtenir les relations et enregistre la colonne "niveaux", ce processus est vraiment lent (à cause des boucles) et j'ai essayé avec un certain cte pour obtenir les relations mais a échoué misérablement.

Jusqu'à présent, j'ai essayé ce cte mais il ne fait pas ce que j'espérais et aussi, il semble reproduire des lignes ...

;With Parents(ProductId, ParentId, Levels)
As(
  Select ProductId, ParentId, Levels
  From Products
  Where ParentId = 0 
  Union All
  Select p.ProductId, p.ParentId, p.Levels
  From Products p
  Join Parents cte On cte.ProductId = p.ParentId
)
Select *
From Parents

Comme je l'ai mentionné plus tôt, nous avons un processus qui boucle la table, il fait son travail mais cela peut prendre jusqu'à 30 minutes, ma question est de savoir s'il existe une meilleure façon de le faire? je sais que CTE me permet de le faire mais je le suce aussi, la colonne des niveaux doit être calculée et mise à jour sur la table, est-ce possible?

Voici un Sqlfiddle au cas où quelqu'un pourrait aider, merci!

15
Sam Ccp

Cela devrait le faire:

WITH MyTest as
(
  SELECT P.ProductID, P.ParentID, CAST(P.ProductID AS VarChar(Max)) as Level
  FROM Products P
  WHERE P.ParentID = 0

  UNION ALL

  SELECT P1.ProductID, P1.ParentID, CAST(P1.ProductID AS VarChar(Max)) + ', ' + M.Level
  FROM Products P1  
  INNER JOIN MyTest M
  ON M.ProductID = P1.ParentID
 )
SELECT * From MyTest

Et voici la mise à jour SQL Fiddle .

Consultez également ce lien pour obtenir de l'aide sur les CTE ... Ils sont vraiment bons à savoir:

J'espère que cela fera l'affaire!

38
John Bustos
;With Parents(ProductId, ParentId, Level, levels)
As(
  Select ProductId, ParentId, 0, 
     cast(ltrim(str(productId,8,0)) as varchar(max))
  From Products
  Where ParentId = 0 
  Union All
  Select p.ProductId, p.ParentId, 
      par.Level + 1,
      cast( levels + ', ' + ltrim(str(productId,8,0)) as varchar(max))
  From Products p
     Join Parents par
        On par.ProductId = p.ParentId
  )
  Select * From Parents
  Order By Level
2
Charles Bretana