2014-05-13 7 views
9

Ich habe eine Eltern-Kind-Beziehungstabelle wie unten gezeigt. Ich möchte alle Datensätze für einen Eltern- oder Kind-ID wie alle Vorfahren und Eltern und wenn möglich mit Tiefe abrufen. Zum Beispiel möchte ich die Familie von D finden, es wird die ersten 14 Zeilen zurückgeben, da alle von der gleichen Familie sind. Es kann mehrere solcher Familien geben. Ich möchte mit einem Mitglied abfragen und will ganze Familie aufnehmen. Ist es möglich, dies unter Verwendung von CTE zu implementieren? Die Familienstrukturen gemäß Tabelle Datensatz:CTE für die Eltern-Kind-Beziehung mit mehreren Elternteilen

     A 
        /\ 
        B C G J 
       / \/\/\ 
       M D  E H K 
      /\/   \/\ 
      N F    I L 


       R 
       | 
       S U 
        \/
        T 

Bitte helfen. Die Tabelle ist wie:

Parent Child 
    ------ ------ 
    A   B 
    A   C 
    B   D 
    D   F 
    M   F 
    M   N 
    C   E 
    G   E 
    G   H 
    J   H 
    J   K 
    H   I 
    K   I 
    K   L 
    R   S 
    S   T 
    U   T 

Danke,

Himadri

+0

Ich weiß, es möglich ist, alle direkten Nachkommen abrufen eine rekursive Abfrage verwenden. Ich bin gespannt, ob jemand eine Lösung für ein vollständiges Diagramm willkürlicher Eltern/Kind-Beziehungen wie diesem hat. –

+0

Zyklische Graphen :) Ich bin kürzlich auf ein Problem dieser Art gestoßen. Ich habe mich daran gehindert, die Tour-Traversal-Geschichte aufzuzeichnen (und sie abzufragen), während die 'rCTE' voranschreitet. Geladen mit einem "WHILE" -Schleife wie hier vorgeschlagen: http://hansolav.net/sql/graphs.html - werde diesen Beitrag im Auge behalten, um zu sehen, was daraus wird. – MarkD

Antwort

1

ich eine Lösung gefunden. Aber ich benutzte CTE in einer while-Schleife. Wenn jemand eine andere Lösung hat, schlagen Sie bitte vor. Wie ich oben erwähnt habe, enthält eine Tabelle Familienaufzeichnungen oder Sie können Diagramme sagen. Sagen wir es als tbl_ParentChild.

Hier ist mein Code:

Declare @Child varchar(10), @RowsEffected int 
Set @Child='D'-----It is the member whose family we want to find 

CREATE Table #PrntChld (Parent varchar(10),Child varchar(10)) 
Insert Into #PrntChld 
Select Parent,Child from tbl_ParentChild MF 
Where [email protected] or [email protected] 

Select @RowsEffected=Count(*) from #PrntChld 

While @RowsEffected>0 
BEGIN 
    ;WITH Prnt(Parent,Child) 
     AS 
     (Select M.Parent,M.Child from tbl_ParentChild M 
      Inner Join #PrntChld F On F.Child=M.Child 
      UNION ALL 
      SELECT e.Parent,e.Child  
       FROM tbl_ParentChild AS E 
       INNER JOIN Prnt AS M     
        ON E.Child = M.Parent   
     ), 
     PrntChld(Parent,Child) 
     AS 
     (Select M.Parent,M.Child from tbl_ParentChild M 
      Inner Join (Select * from Prnt union Select * from #PrntChld) F On M.Parent=F.Parent 
      UNION ALL 
      SELECT e.Parent,e.Child  
       FROM tbl_ParentChild AS E 
       INNER JOIN PrntChld AS M     
        ON M.Child = E.Parent   
     ) 

    Insert Into #PrntChld 
    Select distinct MF.* from PrntChld MF 
    Left Join #PrntChld T On T.Child =MF.Child and T.Parent = MF.Parent  
    where T.Child is null 
    Select @[email protected]@ROWCOUNT 

END 

Select * from #PrntChld 
drop table #PrntChld 
2

Ich werde meine Lösung mit einem String-Begrenzer der Rekursion posten. Ich habe mich gefragt, ob es gut ist, das für eine große Grafik so zu machen, aber ich denke, es ist gar nicht so schlecht. Im Grunde bearbeite ich die Relationen rekursiv, zeichne den "Pfad" auf, der mich zu jedem Schritt gebracht hat, und überprüfe den Pfad, so dass ich aufhören kann, wenn ich auf eine zirkuläre Beziehung stoße.

Für alle, die es versuchen will, bin Entsendung i das Erstellen und Füllen der Tabelle:

create table nodes 
(
    p char, 
    c char 
) 
insert into nodes (p, c) 
values 
    ('A', 'B'), ('A', 'C'), ('B', 'D'), ('D', 'F'), ('M', 'F'), ('M', 'N'), ('C', 'E'), 
    ('G', 'E'), ('G', 'H'), ('J', 'H'), ('J', 'K'), ('H', 'I'), ('K', 'I'), ('K', 'L'), 
    ('R', 'S'), ('S', 'T'), ('U', 'T') 

Und hier ist die Abfrage:

declare @let char = 'D'; 
with cte as 
(
    --get the node itself if it exists in the table at all 
    select 
     top 1 @let as letter, '' as rec_path 
    from 
     nodes 
    where 
     c = @let or p = @let 

    union all 
    -- get the direct relations of the node as a starting point 
    select 
     case when c = @let then p else c end as letter, 
     cast(@let as varchar(max)) as rec_path 
    from 
     nodes 
    where 
     c = @let or p = @let 

    union all 
    -- get all of the relations recursively until you reach a node you already processed 
    select 
     case when c = cte.letter then p else c end as letter, 
     rec_path + cte.letter as rec_path 
    from 
     cte 
     join nodes on 
      (cte.letter = nodes.c and charindex(cast(nodes.p as varchar(1)), rec_path, 1) = 0 
      or (cte.letter = nodes.p and charindex(cast(nodes.c as varchar(1)), rec_path, 1) = 0)) 
) 
select 
    distinct letter 
from 
    cte 

Ich hoffe, dass es nützlich sein wird . Ich weiß, dass Ihre Daten nicht wirklich aus Buchstaben bestehen, aber das Gleiche kann mit id-s gemacht werden, indem wieder ein String-Pfad oder sogar ein XML verwendet wird.

0

Diese Lösung funktioniert nur mit azyklischen Graphen, da die Rekursion bricht, wenn sie zyklisch läuft und den Datensatz als geliefert akzeptiert ...

create table nodes 
(
    p char, 
    c char 
) 
insert into nodes (p, c) 
values 
    ('A', 'B'), ('A', 'C'), ('B', 'D'), ('D', 'F'), ('M', 'F'), ('M', 'N'), ('C', 'E'), 
    ('G', 'E'), ('G', 'H'), ('J', 'H'), ('J', 'K'), ('H', 'I'), ('K', 'I'), ('K', 'L'), 
    ('R', 'S'), ('S', 'T'), ('U', 'T') 

GO 

Wir können die Vorwärts-Baum Eltern bekommen -> Kind durch Rekursion über den ursprünglichen Knotendatensätze

CREATE VIEW dbo.Tree 
AS 
    WITH Hierarchy(r, p, c, [Level]) 
    AS 
    (
     SELECT p AS r, 
       p, 
       c, 
       0 AS [Level] 
     FROM dbo.nodes 
     UNION ALL 
     SELECT n.p AS r, 
       t.p, 
       t.c, 
       t.[Level] + 1 
     FROM Hierarchy t 
     INNER JOIN dbo.nodes n ON n.c = t.r 
     AND n.p != t.p 
    ) 
    SELECT r, p, c, [Level] 
    FROM Hierarchy 

Das gibt dann das Ergebnis

r p c Level 
A A B 0 
A A C 0 
A C E 1 
A D F 2 
A B D 1 
B D F 1 
B B D 0 
C C E 0 
D D F 0 
G G E 0 
G G H 0 
G H I 1 
H H I 0 
J H I 1 
J K L 1 
J K I 1 
J J H 0 
J J K 0 
K K I 0 
K K L 0 
M M F 0 
M M N 0 
R R S 0 
R S T 1 
S S T 0 
U U T 0 

Wir können dann dies tun, das andere So können wir von einem Kind bis zu seinen Eltern gehen.

CREATE VIEW dbo.ReverseTree 
AS 
    WITH Hierarchy(r, c, p, [Level]) 
    AS 
    (
     SELECT c AS r, 
       c, 
       p, 
       0 AS [Level] 
     FROM dbo.nodes 
     UNION ALL 
     SELECT n.c AS r, 
       t.c, 
       t.p, 
       t.[Level] + 1 
     FROM Hierarchy t 
     INNER JOIN dbo.nodes n ON n.p = t.r 
     AND n.c != t.c 
    ) 
    SELECT r, c, p, [Level] 
    FROM Hierarchy 

Und die Ergebnisse aus, dass so aussehen

r c p Level 
B B A 0 
C C A 0 
D D B 0 
D B A 1 
E C A 1 
E E C 0 
E E G 0 
F F D 0 
F F M 0 
F D B 1 
F B A 2 
H H G 0 
H H J 0 
I I H 0 
I I K 0 
I K J 1 
I H J 1 
I H G 1 
K K J 0 
L K J 1 
L L K 0 
N N M 0 
S S R 0 
T T S 0 
T T U 0 
T S R 1 

Das für Dinge wie Brotkrümel praktisch ist, schleppt