web-dev-qa-db-fra.com

ORDRE hiérarchique de l'arbre parent-enfant

Je dois suivre les données dans SQL Server 2008 R2. SQLFiddle

Schéma:

 CRÉER UN TABLEAU [dbo]. [ICFilters] (
 [ICFilterID] [int] IDENTITY (1,1) NOT NULL, 
 [ParentID] [int] NOT NULL DEFAULT 0 , 
 [FilterDesc] [varchar] (50) NOT NULL, 
 [Active] [tinyint] NOT NULL DEFAULT 1, 
 CONTRAINT [PK_ICFilters] PRIMARY KEY CLUSTERED 
 ([ICFilterID] ASC) AVEC 
 PAD_INDEX = OFF, 
 STATISTICS_NORECOMPUTE = OFF, 
 IGNORE_DUP_KEY = OFF, 
 ALLOW_ROW_LOCKS = ON, 
 ALLOW_PAGE_LOCKS = ON 
) ON [PRIMARY] 
) ON [PRIMARY] 
 
 INSERT INTO [dbo]. [ICFilters] (ParentID, FilterDesc, Active) 
 Valeurs 
 (0, 'Product Type', 1), 
 (1, 'ProdSubType_1', 1), 
 (1, 'ProdSubType_2', 1), 
 (1, 'ProdSubType_3', 1), 
 (1, 'ProdSubType_4', 1), 
 (2, 'PST_1.1', 1), 
 (2, 'PST_1.2', 1), 
 (2, 'PST_1.3', 1), 
 (2, 'PST_1.4', 1), 
 (2, 'PST_1.5', 1), 
 (2, 'PST_1.6', 1), 
 (2, 'PST_1.7', 0), 
 (3, 'PST_2.1', 1), 
 (3, 'PST_2.2', 0), [._ ___.] (3, 'PST_2.3', 1), 
 (3, 'PST_2.4', 1), 
 (14, 'PST_2.2.1', 1), 
 (14, 'PST_2.2.2', 1), 
 (14, 'PST_2.2.3', 1), 
 (3, 'PST_2.8', 1) 

Table:

 | ICFILTERID | PARENTID | FILTERDESC | ACTIF | 
 ------------------------------------------- ------- 
 | 1 | 0 | Type de produit | 1 | 
 | 2 | 1 | ProdSubType_1 | 1 | 
 | 3 | 1 | ProdSubType_2 | 1 | 
 | 4 | 1 | ProdSubType_3 | 1 | 
 | 5 | 1 | ProdSubType_4 | 1 | 
 | 6 | 2 | PST_1.1 | 1 | 
 | 7 | 2 | PST_1.2 | 1 | 
 | 8 | 2 | PST_1.3 | 1 | 
 | 9 | 2 | PST_1.4 | 1 | 
 | 10 | 2 | PST_1.5 | 1 | 
 | 11 | 2 | PST_1.6 | 1 | 
 | 12 | 2 | PST_1.7 | 0 | 
 | 13 | 3 | PST_2.1 | 1 | 
 | 14 | 3 | PST_2.2 | 0 | 
 | 15 | 3 | PST_2.3 | 1 | 
 | 16 | 3 | PST_2.4 | 1 | 
 | 17 | 14 | PST_2.2.1 | 1 | 
 | 18 | 14 | PST_2.2.2 | 1 | 
 | 19 | 14 | PST_2.2.3 | 1 | 
 | 20 | 3 | PST_2.8 | 1 | 

Chaque ligne a l'ID de son parent et le parentid = 0. Les FilterDesc ne sont que des exemples de descriptions, donc je ne peux pas essayer de les analyser pour les commander.

La question

Est-il possible de sélectionner toutes les lignes de manière arborescente? Si c'est le cas, comment? Quand je dis "en forme d'arbre", je veux dire sélectionner récursivement le parent suivi par tous ses enfants, puis tous les enfants de chacun d'entre eux et ainsi de suite. Une première traversée d'arbre en profondeur.

Mes amis et moi avons essayé, mais nous n'avons pas réussi à trouver des solutions de travail, mais nous continuerons d'essayer. Je suis assez nouveau dans sql, donc cela peut être fait facilement et je rends les choses plus difficiles que nécessaire.

Exemple de sortie (souhaitée):

 | ICFILTERID | PARENTID | FILTERDESC | ACTIF | 
 ------------------------------------------- ------- 
 | 1 | 0 | Type de produit | 1 | 
 | 2 | 1 | ProdSubType_1 | 1 | 
 | 6 | 2 | PST_1.1 | 1 | 
 | 7 | 2 | PST_1.2 | 1 | 
 | 8 | 2 | PST_1.3 | 1 | 
 | 9 | 2 | PST_1.4 | 1 | 
 | 10 | 2 | PST_1.5 | 1 | 
 | 11 | 2 | PST_1.6 | 1 | 
 | 12 | 2 | PST_1.7 | 0 | 
 | 3 | 1 | ProdSubType_2 | 1 | 
 | 13 | 3 | PST_2.1 | 1 | 
 | 14 | 3 | PST_2.2 | 0 | 
 | 17 | 14 | PST_2.2.1 | 1 | 
 | 18 | 14 | PST_2.2.2 | 1 | 
 | 19 | 14 | PST_2.2.3 | 1 | 
 | 15 | 3 | PST_2.3 | 1 | 
 | 16 | 3 | PST_2.4 | 1 | 
 | 20 | 3 | PST_2.8 | 1 | 
 | 4 | 1 | ProdSubType_3 | 1 | 
 | 5 | 1 | ProdSubType_4 | 1 | 
21
Archangel33

OK, assez de cellules cérébrales sont mortes.

SQL Fiddle

WITH cte AS
(
  SELECT 
    [ICFilterID], 
    [ParentID],
    [FilterDesc],
    [Active],
    CAST(0 AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters]
  WHERE [ParentID] = 0
  UNION ALL
  SELECT 
    i.[ICFilterID], 
    i.[ParentID],
    i.[FilterDesc],
    i.[Active],  
    Level + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters] i
  INNER JOIN cte c
    ON c.[ICFilterID] = i.[ParentID]
)

SELECT 
  [ICFilterID], 
  [ParentID],
  [FilterDesc],
  [Active]
FROM cte
ORDER BY [Level];
25
Travis

Ce qui précède ne semble pas fonctionner correctement pour moi. Imaginez une configuration à 2 tables avec des données de type facebook. Le tableau 1, a PostId + vous d'autres champs. PostId est incrémenté automatiquement et, évidemment, dans votre interface, vous trierez DESC pour avoir le dernier message en haut.

Maintenant, pour le tableau des commentaires. Tableau 2 Ce tableau CommentId est la clé primaire, numéro automatique. Dans votre interface graphique, vous souhaitez l'afficher en ASC, de sorte que lors de la lecture du fil, cela ait du sens. (le plus ancien (nombre le plus petit) en haut) Les autres clés importantes du tableau 2 sont: PostId (FK retour aux publications) et ParentId (FK à CommentId) où ParentId sera NULL s'il s'agit du commentaire "racine" sur une publication. Si quelqu'un RÉPOND à un commentaire, alors le parentId sera rempli avec le commentid.
J'espère que vous aurez compris. Le CTE ressemblera à ceci:

WITH  Comments
        AS ( SELECT  CommentId , ParentId, CAST(CommentId AS VARBINARY(MAX)) AS Sortkey, 0 AS Indent
             FROM    dbo.Comments
             WHERE   ParentId IS NULL AND PostId = 105
             UNION ALL
             SELECT  b.CommentId , b.ParentId,  c.Sortkey + CAST(b.CommentId AS varbinary(max))  AS Sortkey, c.Indent + 1 AS Indent
             FROM    dbo.Comments b
             INNER JOIN Comments c ON c.CommentId = b.ParentId
           )
   SELECT   *
   FROM     Comments
   ORDER BY Sortkey

Exemple de sortie

1   NULL    0x0000000000000001  0
5   1   0x00000000000000010000000000000001  1
6   5   0x000000000000000100000000000000010000000000000005  2
2   NULL    0x0000000000000002  0

Sur F/B post 105, il y avait deux commentaires (CommentIds 1 et 2) Quelqu'un a ensuite répondu sur Comment1 (CommentId 5, ParentId 1), puis quelqu'un d'autre a commenté cette réponse, ainsi de suite Comment5 (CommentId 6, ParentId 6)

Et l'alto, la séquence est correcte, sous le post, vous pouvez maintenant afficher les commentaires dans la bonne séquence. Pour mettre en retrait les messages afin qu'ils se forment et se dessinent comme dans Facebook (plus le niveau est profond, plus il doit être margé à partir de la gauche), j'ai également une colonne appelée Retrait. Les racines sont 0, puis dans l'union, nous avons c.Indent + 1 AS Indent Dans le code, vous pouvez maintenant multiplier le retrait avec laisse supposer 32px, et afficher les commentaires dans une hiérarchie et un contour Nice.

Je ne vois aucun problème à utiliser la clé primaire d'incrémentation automatique CommentId comme force motrice pour la création de ma SortKey, car il y a un meilleur changement de vous gâcher les dates (date de commentaire) que de gâcher une clé gérée par la base de données qui contient +1

1
Guss Davey
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
insert into pc values('b','f');
insert into pc values('a','d');
Insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');

 DECLARE @parent varchar(10) = 'a';
 WITH cte AS
 (
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
  FROM pc a JOIN cte c ON a.parent = c.child
  )
  SELECT distinct parent, child , level
  FROM cte
  order by level, parent

Cela vous donnera tous les descendants et le niveau.
J'espère que cela t'aides :)

0
Wohoooo