Parent-Child Tree Hierarchical ORDER


21

Ich muss Daten in SQL Server 2008 R2 folgen. SQLFiddle

Schema:

CREATE TABLE [dbo]. [ICFilters] (
   [ICFilterID] [int] IDENTITY (1,1) NOT NULL,
   [ParentID] [int] NOT NULL DEFAULT 0,
   [FilterDesc] [varchar] (50) NICHT NULL,
   [Aktiv] [tinyint] NOT NULL DEFAULT 1,
 CONSTRAINT [PK_ICFilters] PRIMARY KEY CLUSTERED 
 ([ICFilterID] ASC) WITH 
    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)
Werte 
(0, 'Produkttyp', 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)

Tabelle:

| ICFILTERID | PARENTID | FILTERDESC | AKTIV |
--------------------------------------------------
| 1 | 0 | Produkttyp | 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 |

Jede Zeile hat die ID des übergeordneten Elements und des Stammelements parentid = 0. Die FilterDescs sind nur Beispielbeschreibungen, daher kann ich nicht versuchen, diese für die Bestellung zu analysieren.

Die Frage

Ist es möglich, alle Zeilen baumartig auszuwählen? Wenn das so ist, wie? Wenn ich "baumartig" sage, meine ich, rekursiv den Elternteil auszuwählen, gefolgt von allen seinen Kindern, dann allen Kindern von jedem von diesen und so weiter. Eine erste Baumdurchquerung der Tiefe.

Meine Freunde und ich haben es versucht, aber wir haben keine funktionierenden Lösungen gefunden, werden es aber weiter versuchen. Ich bin ziemlich neu in SQL, also kann das vielleicht leicht gemacht werden und ich mache die Dinge nur schwieriger als nötig.

Beispiel (gewünschte) Ausgabe:

| ICFILTERID | PARENTID | FILTERDESC | AKTIV |
--------------------------------------------------
| 1 | 0 | Produkttyp | 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 |

Wäre am besten CTE
Kin Shah

1
Hier ist ein Thread, der die gewünschte Ergebnissortierung anzeigt, ohne dass Tabellendaten in einer bestimmten Reihenfolge geladen werden müssen. Es verwendet row_number () und partition by, um einen "Pfad" zu erstellen, der die gewünschte Sortierung ermöglicht. ask.sqlservercentral.com/questions/48518/…

Antworten:


25

Okay, genug Gehirnzellen sind tot.

SQL-Geige

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];

2
Genau das habe ich gebraucht! Ich bin damit einverstanden, dass zu viele Gehirnzellen daran gestorben sind. War mir nicht klar, was ich wollte? In diesem Fall bearbeite ich die Frage zur späteren Bezugnahme. Ich habe es definitiv schwieriger gemacht, als es sein musste ...
Erzengel33,

1
@ Archangel33 Du hast gute Arbeit geleistet, um das Problem zu klären und was du brauchst. Außerdem hilft sqlfiddle wirklich.
Travis

2
1 , aber unter Verwendung von [ICFilterID] [int] IDENTITY (1,1) für nur Sortierung wird es Elemente arbeiten , werden in der richtigen Reihenfolge eingefügt, sondern ein anderes Feld für die Sortierung ist noch nicht von OT umgesetzt
Bummi

4
Ich glaube nicht, dass dies eine 100% richtige Lösung ist. Obwohl alle Zeilen mit der korrekten Ebene in der Hierarchie aufgelistet werden, wird sie nicht in der Reihenfolge aufgelistet, in der sie gefragt wurden. Wäre es möglich, die Zeilen in der richtigen Reihenfolge gemäß der Frage aufzulisten? Das suche ich auch.

1
Dies beantwortet meine Frage, da die in der [FilterDesc]Spalte angegebenen Daten fiktiv sind und diese Reihenfolge unnötig / unwichtig ist. Gemäß der Logik in der Antwort von @Travis Gan muss nur eine weitere hinzugefügt werden, um diese Bestellung CASTzu erhalten Level. z.B. Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS LevelWird Level + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Level.
Erzengel33

1

Das obige scheint bei mir nicht richtig zu funktionieren. Stellen Sie sich ein 2-Tabellen-Setup mit Facebook-Datentyp vor. Tabelle 1, hat PostId + Ihnen andere Felder. Die Post-ID wird automatisch inkrementiert, und natürlich werden Sie in Ihrer Benutzeroberfläche DESC so sortieren, dass der neueste Beitrag ganz oben steht.

Nun zur Kommentartabelle. Tabelle 2 Diese Tabelle CommentId ist der Primärschlüssel, die automatische Nummer. In Ihrer GUI möchten Sie es als ASC anzeigen, damit es beim Lesen des Threads Sinn macht. (älteste (kleinere Zahl) oben) Andere wichtige Schlüssel in Tabelle 2 sind: PostId (FK zurück zu Posts) und ParentId (FK zu CommentId), wobei ParentId NULL ist, wenn dies der "Root" -Kommentar eines Posts ist. Wenn jemand auf einen Kommentar ANTWORTET, wird die parentId mit der commentid gefüllt.
Ich hoffe, ihr habt den Drift verstanden. Der CTE wird folgendermaßen aussehen:

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

Beispielausgabe

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

In F / B-Beitrag 105 gab es zwei Kommentare (CommentIds 1 und 2). Jemand antwortete dann auf Comment1 (CommentId 5, ParentId 1), und dann kommentierte jemand anderes diese Antwort, also auf Comment5 (CommentId 6, ParentId 6).

Und Viola, die Reihenfolge stimmt, unter dem Beitrag können Sie nun die Kommentare in der richtigen Reihenfolge anzeigen. Um die Beiträge so einzurücken, dass sie sich wie in Facebook formen und gliedern (je tiefer die Ebene ist, desto mehr muss sie von links eingegrenzt werden), habe ich auch eine Spalte namens Einrücken. Die Wurzeln sind 0 und dann in der Vereinigung haben wir c.Indent + 1 AS Indent Im Code können Sie jetzt den Einzug mit lets annehmen 32px multiplizieren und die Kommentare in einer schönen Hierarchie und Gliederung anzeigen.

Ich sehe kein Problem darin, den Auto-Inkrement-Primärschlüssel CommentId als treibende Kraft für die Erstellung meines SortKey zu verwenden, da es eine bessere Veränderung gibt, wenn Sie Daten (commentdate) verfälschen, als wenn Sie einen von der Datenbank verwalteten Schlüssel verfälschen, der +1 ergibt


0
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

Dies gibt Ihnen alle Nachkommen und die Ebene.
Hoffe das hilft :)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.