Damit rekursive CTE Besuch Knoten mehrfach
Betrachten Sie die folgenden einfachen DAG:
1->2->3->4
Sowie eine Tabelle, #bar, beschreiben (ich bin die mit SQL Server 2005):
parent_id child_id
1 2
2 3
3 4
//... other edges, not connected to the subgraph above
Jetzt Stell dir vor, ich habe einige andere willkürliche Kriterien, wählen Sie den ersten und den letzten Kanten, d.h. 1->2-und 3->4. Ich möchte, um diese zu finden, den rest meines graph.
Kann ich schreiben Sie eine rekursive CTE wie folgt (ich verwende die Terminologie von MSDN):
with foo(parent_id,child_id) as (
// anchor member that happens to select first and last edges:
select parent_id,child_id from #bar where parent_id in (1,3)
union all
// recursive member:
select #bar.* from #bar
join foo on #bar.parent_id = foo.child_id
)
select parent_id,child_id from foo
Jedoch, diese Ergebnisse in Rand-3->4 als zweimal gewählt:
parent_id child_id
1 2
3 4
2 3
3 4 // 2nd appearance!
Wie kann ich verhindern, dass die Abfrage von recursing in Teilgraphen, die bereits beschrieben worden? Könnte ich erreichen, wenn, in meinem "Rekursives Element" - Teil der Abfrage, könnte ich die Referenz alle Daten, die abgerufen wurde, der vom rekursiven Allgemeinen Tabellenausdruck so weit (und liefern ein Prädikat, das angibt, in das rekursive Element ohne Knoten bereits besucht). Ich denke aber, ich kann auf Daten zugreifen, die zurückgegeben wurde der letzten iteration des rekursiven Elements nur.
Das wird nicht gut skalieren, wenn es eine Menge solcher Wiederholung. Gibt es eine Möglichkeit, dies zu verhindern unnötige zusätzliche Rekursion?
Beachten Sie, dass ich verwenden könnte, "select distinct" in der letzten Zeile meiner Anweisung, um die gewünschten Ergebnisse zu erreichen, aber dies scheint angewandt werden nach alle die (wiederholt) die Rekursion erfolgt, so dass ich nicht denke, dass das eine ideale Lösung.
Bearbeiten - hainstech schlägt vor, stoppen die Rekursion durch ein Prädikat hinzufügen ausschließen recursing Wege beschritten wurden, die explizit in den ersten Satz, D. H. recurse nur where foo.child_id not in (1,3)
. Das funktioniert für den oben genannten Fall nur, weil Sie es sich einfach - alle wiederholten Abschnitten, beginnen die Anker Menge von Knoten. Löst es nicht den Allgemeinen Fall, wo Sie vielleicht nicht. beispielsweise, betrachten Sie das hinzufügen von Kanten 1->4 und 4->5 zu den oben genannten Satz. Edge-4->5 erfasst werden, um die zweimal, einmal mit den vorgeschlagenen Prädikat. 🙁
InformationsquelleAutor der Frage bacar | 2009-05-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den
CTE
's sind rekursiv.Wenn Ihr
CTE
's mehrere, die Anfangsbedingungen, das heißt, Sie haben auch verschiedene Rekursion-Stapel, und es gibt keinen Weg, um Informationen von einem Stapel in einen anderen stack.In deinem Beispiel die Rekursion-Stapel wird gehen Sie wie folgt vor:
Wie Sie sehen können, diese Rekursion stack nicht überschneiden.
Könnte Sie wahrscheinlich Aufzeichnung der besuchten Werte in eine temporäre Tabelle
JOIN
jeder Wert mit der temptable und tun nicht Folgen Sie diesen Wert, wenn es gefunden wurde, aberSQL Server
unterstützt nicht diese Dinge.So verwenden Sie einfach
SELECT DISTINCT
.InformationsquelleAutor der Antwort Quassnoi
Dies ist der Ansatz, den ich verwendet. Es wurde getestet, gegen mehrere Methoden, und Sie war die meiste Leistung bietet. Es vereint die temp-Tabelle Anregung von Quassnoi und die Verwendung von distinct und einen left join, um redundante Pfade zu der Rekursion. Die Ebene der Rekursion ist auch enthalten.
Verließ ich das versäumt CTE-Ansatz in den code, so könnte man die Ergebnisse vergleichen.
Wenn jemand eine bessere Idee hat, ich würde lieben, es zu wissen.
InformationsquelleAutor der Antwort Laramie
Tun Sie geschehen, zu wissen, welche der beiden Kanten ist auf einer tieferen Ebene im Baum? Da in diesem Fall, man könnte die Kante
3->4
das Ankerelement und starten Sie zu Fuß auf den Baum, bis Sie finden, edge1->2
.Etwas wie dieses:
InformationsquelleAutor der Antwort Ronald Wildenberg
Ist das, was Sie tun wollen?
Edit - @in der Bacar - ich glaube nicht, das ist der temp-Tabelle-Lösung Quasnoi vorschlägt. Ich glaube, Sie waren im Grunde darauf hindeutet, duplizieren Sie die gesamte Rekursion Mitglied Inhalt bei jeder Rekursion, und verwenden Sie einen join, um zu verhindern, dass die Wiederaufbereitung (und dass diese nicht unterstützt wird ss2k5). Mein Ansatz unterstützt wird, und die einzige Veränderung, die Ihre Vorlage wird in das Prädikat in der Rekursion Mitglied ausschließen recursing Wege beschritten wurden, die explizit in Ihrem ersten Satz. Ich habe nur Hinzugefügt die Tabelle Variablen, so dass definieren Sie die Start-parent_ids in einem Ort, könnte man genauso leicht verwendet haben, dieses Prädikat mit Ihrer ursprünglichen Abfrage:
InformationsquelleAutor der Antwort ahains
BEARBEITEN -- Diese funktioniert überhaupt nicht. Dies ist eine Methode, um zu stoppen jagen Dreieck Strecken. Es nicht zu tun, was der OP wollte.
Oder Sie verwenden eine rekursive token-getrennter string.
Ich bin zu Hause auf meinem laptop ( kein sql-server ), so könnte dies nicht vollkommen richtig, aber hier geht.....
Oder ähnliches. Sorry, Es ist spät und ich kann nicht testen. Ich check am Montag morgen. Gutschrift für das muss Peter Larsson (Peso)
Wurde die Idee generiert, hier:
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=115290
InformationsquelleAutor der Antwort Transact Charlie
(Ich bin kein Experte auf Graphen, nur die Erkundung einer bit)
DISTINCT garantieren jede Zeile eindeutig ist, aber es nicht beseitigen graph Routen, die nicht am Ende in Ihrem letzten Kante. Nehmen Sie dieses Diagramm:
Die Ergebnisse der Abfrage sind hier (1,5), die nicht Teil der route, von der ersten Kante (1,2) auf der letzten Kante (6,4).
Könnten Sie versuchen, so etwas wie dieses, nur die Routen, die beginnen mit (1,2) und Ende mit (6,4):
InformationsquelleAutor der Antwort Andomar