2017-08-16 9 views
3

Ich arbeite mit einigen Tabellen, die ein Dateisystem darstellen, und ich muss den vollständigen Pfad jedes Ordners als eine abgeflachte Zeichenfolge auswählen.SQL - Nicht-Null-Adjazenzliste in Pfad konvertieren

Die erste Tabelle enthält die Details der einzelnen Ordner:

CREATE TABLE Folders(
    FolderID int IDENTITY(1,1) NOT NULL, 
    [Name] nvarchar(255) NOT NULL) 

Die zweite Tabelle enthält transitiv Schließungen von Ordner Beziehungen:

CREATE TABLE FolderClosures(
    FolderClosuresID int IDENTITY(1,1) NOT NULL, 
    AncestorFolderID int NOT NULL, --Foreign key to Folders.FolderID 
    DescendantFolderID int NOT NULL --Foreign key to Folders.FolderID 
    IsDirect bit NOT NULL) 

Für Beispieldaten, nehmen wir an, die folgenden Ordner vorhanden sind:

Documents/ 
Documents/Finance/ 
Documents/HumanResources/ 
Documents/HumanResources/Training/ 

Diese würden in diesen Tabellen wie folgt beibehalten werden :

| FolderID | Name   | 
+----------+----------------+ 
|  1 | Documents  | 
|  2 | Finance  | 
|  3 | HumanResources | 
|  4 | Training  | 

| FolderClosureID | AncestorFolderID | DescendantFolderID | IsDirect | 
+-----------------+------------------+--------------------+----------+ 
|    1 |    1 |     1 |  0 | 
|    2 |    2 |     2 |  0 | 
|    3 |    1 |     2 |  1 | 
|    4 |    3 |     3 |  0 | 
|    5 |    1 |     3 |  1 | 
|    6 |    4 |     4 |  0 | 
|    7 |    1 |     4 |  0 | 
|    8 |    3 |     4 |  1 | 

Einige Details zu beachten:

  1. Jeder Ordner hat eine "Identität Reihe" in FolderClosures, wo AncestorFolderID = DescendantFolderID AND IsDirect = 0.

  2. Jeder Ordner, kein Ordner der obersten Ebene ist genau eine Zeile in FolderClosures wo IsDirect = 1

  3. FolderClosures viele Zeilen pro Ordner enthalten kann, wo AncestorFolderID <> DescendantFolderID AND IsDirect = 0. Jedes von diesen stellt eine "Großeltern" oder entferntere Beziehung dar.

  4. Da keine Spalten nullfähig sind, geben keine Zeilen explizit an, dass ein bestimmter Ordner ein Ordner der obersten Ebene ist. Dies kann nur festgestellt werden, indem überprüft wird, dass in FolderClosuresIsDirect = 1 AND DescendantFolderID = SomeID keine Zeilen vorhanden sind, wobei SomeID die ID des betreffenden Ordners ist.

Ich möchte in der Lage sein, eine Abfrage auszuführen, die diese Daten zurückgibt:

| FolderID | Path        | 
+----------+------------------------------------+ 
|  1 | Documents/       | 
|  2 | Documents/Finance/     | 
|  3 | Documents/HumanResources/   | 
|  4 | Documents/HumanResources/Training/ | 

Ordner in beliebiger Tiefe verschachtelt werden kann, aber realistisch wahrscheinlich nur bis zu 10 Ebenen. Abfragen erfordern möglicherweise das Zurückgeben von Pfaden für einige tausend Ordner.

Ich habe eine Menge Tipps zum Erstellen dieser Art von Abfrage gefunden, wenn Daten als Adjazenzliste persistent sind, aber ich konnte keine Antwort für eine transitive Schließung Setup wie folgt finden. Die Adjazenzlisten-Lösungen, die ich gefunden habe, verlassen sich darauf, dass Zeilen mit nullbaren übergeordneten Ordner-IDs beibehalten werden, aber das funktioniert hier nicht.

Wie kann ich die gewünschte Ausgabe erhalten?

Wenn es hilft, ich bin mit SQL Server 2016.

Antwort

2

Eine Möglichkeit, gewünschte Ausgabe zu erhalten, ist eine rekursive Abfrage zu tun. Ich denke, das Beste ist, nur die Zeilen zu verwenden, die IsDirect = 1 haben, und den Anker als alle Ordner zu verwenden, die in FolderClosures, die alle Ihre Stammordner sein sollten, nicht direkt übergeordnete haben.

WITH FoldersCTE AS (
    SELECT F.FolderID, CAST(F.Name as NVARCHAR(max)) Path 
    FROM Folders F 
    WHERE NOT EXISTS (
     SELECT 1 FROM FolderClosures FC WHERE FC.IsDirect = 1 AND FC.DescendantFolderID = F.FolderID 
    ) 
    UNION ALL 
    SELECT F.FolderID, CONCAT(PF.Path, '\', F.Name) 
    FROM FoldersCTE PF 
      INNER JOIN FolderClosures FC 
       ON FC.AncestorFolderID = PF.FolderId 
       AND FC.IsDirect = 1 
      INNER JOIN Folders F 
       ON F.FolderID = FC.DescendantFolderID 
) 
SELECT * 
FROM FoldersCTE 
OPTION (MAXRECURSION 1000) --> how many nested levels you think you will have 

Dies erzeugt:

FolderID Path 
1   Documents 
2   Documents\Finance 
3   Documents\HumanResources 
4   Documents\HumanResources\Training 

Hoffe, es hilft.