2016-05-20 9 views
1

Ich habe eine kommerzielle Anwendung mit einer SQL Server 2008 R2-Datenbank, die eine Tabelle enthält, die eine Datei- und Ordnerstruktur modellieren soll, ähnlich < root>: < Unterebene 1 >: < Unterebene 2> .. < Unterebene>: < Dokument>. Die Datenbanktabelle enthält Wertepaare (folder_item, übergeordnetes Element), wobei folder-item entweder ein Dokument oder ein Ordner ist und parent ein Link zu einer anderen Zeile in der Tabelle ist.SQL Server rekursive hierarchische Abfrage, weniger als optimale Datenstruktur

Ich versuche, eine Abfrage zu schreiben, die zwei Werte pro Zeile zurückgibt:

  • ein Dokument
  • Der vollständige verketteten Pfad zu dem Dokument, von der obersten Ebene Ordner in den unmittelbaren Behälter des Dokuments, zum Beispiel Wurzel: Level1: Level2 ..: LevelN.

Normalerweise sollte eine rekursive Abfrage der Lage sein, diese Situation zu bewältigen, aber es ist eine Komplikation. Die Ordnerelementtabelle enthält redundante Einträge für jedes Dokument und jede Unterebene, die mit jedem Vorgänger in der Ordnerstruktur und nicht nur mit dem unmittelbaren übergeordneten Element verknüpft werden.

Statt (Dokument, parent) (parent, Großeltern) (Großeltern, Urgroßelternteil) ... (Vorfahre, root)

Die Tabelle enthält (Dokument, parent) (Dokument, Großeltern eltern~~POS=HEADCOMP) ... (Dokument, Vorfahr) (Dokument, root) (parent, Großeltern eltern~~POS=HEADCOMP) ... (parent, Vorfahr) (parent, root) ... (Großelternteil, Urgroßelternteil) ... (Großeltern, Wurzel)

und so weiter. Ich bin sicher, dass die Datenmodellierer ihre Gründe für das Design hatten, aber es negiert die Verwendung einer standardmäßigen rekursiven hierarchischen Abfrage. In der Tat, als ich es versuchte, überschritt die Ausführung die maximale Anzahl von Rekursionsstufen.

Hat jemand anderes ein ähnliches Problem festgestellt, und kann es gelöst werden, ohne auf komplexe Programmierung jenseits der SQL-Standardfunktionen zurückgreifen zu müssen?

Dank viel

Patrick

+0

Wie wäre es, einige Tabellenstrukturen und Beispieldaten zu veröffentlichen? Wenn Sie Ihre Rekursion nur auf den Namen stützen, kämpfen Sie wahrscheinlich einen verlorenen Kampf. –

+0

Die Rekursion basiert auf einem eindeutigen, aber nicht PK-VARCHAR-Wert "DOCNUMBER", wobei die Spalte PARENT die DOCNUMBER der Vorgängerzeile enthält. –

+0

Glücklicherweise stellt sich heraus, dass eine Entscheidung getroffen wurde, die bestehende Ordnerhierarchie zu ignorieren, und das Problem ist dank einer (weisen) geschäftlichen Entscheidung ausnahmsweise verschwunden. Danke an Sean und Tab für die Antwort. –

Antwort

0

Wenn Sie haben:

(Dokument, Eltern) (Dokument, Großeltern) ... (Dokument, Vorfahr) (Dokument, Wurzel) (Eltern, Großeltern) ... (Eltern, Vorfahren) (Eltern, Wurzel) ... (Großeltern, Urgroßeltern) ...(Zucht-, root)

Sie möchten Ihre Rekursion beschränken:

(Dokument, Eltern) (Eltern, Großeltern) (Großeltern, Urgroßeltern) (Urgroßeltern, root)

richtig? Der Trick besteht also darin, herauszufinden, welche Bedingung (en) auf die untere Hälfte der rekursiven CTE gesetzt werden sollen, damit nicht JEDER Verwandte der aktuellen Zeile mit der aktuellen Zeile verbunden wird.

So für document möchten Sie parent. Für parent möchten Sie grandparent und so weiter. Wie können wir diesen Filter erstellen?

Gut für document Was ist wahr über parent das stimmt nicht über andere Vorfahren?

Antwort: document hat alle die gleichen Verwandten wie parent tut, aber nur document hat parent als Vorfahre.

So, wie Sie die Eltern für jedes folder_item betrachten, wenn es eine andere Zeile gibt, in der das übergeordnete Element dieses Parents das selbe ist wie ein Elternelement des aktuellen Elements, dann ist dieses folder_item nicht das unmittelbare übergeordnete Element des aktuellen folder_item und sollte Aus dem rekursiven Join herausgefiltert werden.

Bild ein Interview: "Sie sind also einer meiner Vorfahren. Wenn keiner meiner anderen Vorfahren Sie auch als Vorfahren hat, dann müssen Sie mein unmittelbarer Elternteil sein."

Wahr, nicht?

Ich habe Ihre Struktur nicht mit zu testen, aber ich stelle mir vor, so etwas zu Ihrem rekursiven Hinzufügen beitreten funktionieren würde, aber es kann einige Optimierungen benötigen ...

{for recursion -- Join second half of UNION back to main CTE} 
ON bottom.Folder_Item=cte.parent --you are my ancestor 
AND NOT EXISTS(
SELECT * FROM MyTable mt --others 
WHERE mt.folder_item<>bottom.folder_item --the other is not you 
AND mt.Folder_Item=cte.parent --the other is also my ancestor 
AND mt.Parent=bottom.folder_item --the other also has you as ancestor 
) 

Für diesen Schnipsel bottom ist mein Alias ​​für die untere Hälfte Ihrer rekursiven UNION, und cte ist der Alias ​​des gesamten CTE.

Und indem ich diesen Filter in die JOIN-Bedingung für die Rekursion setze, denke ich, sollte er verhindern, dass der Rekursionsbaum verrückt wird und die Rekursionsgrenze überschreitet. I denken!

Wenn Sie immer noch das Rekursionslimit erhalten, versuchen Sie, Ihre Tabelle auf diese Weise in einem CTE vor Ihrem rekursiven CTE vorzufiltern, damit Sie alle nicht-unmittelbaren Vorfahren vor der Rekursion eliminieren.

Ich denke, das sollte funktionieren können, aber wenn nicht, können Sie definitiv tun, was Sie mit einem CURSOR brauchen.

Verwandte Themen