2017-08-30 3 views
1

Ich habe eine Datenbanktabelle mit verschachtelten URLs strukturiert, mit ParentID und ID zu sagen, welcher Teil einer URL wo gehört.Rekursiv verschachtelte URLs aus der Datenbank

Tabellenstruktur sieht wie folgt aus:

+-----+----------+------------+-------------+ 
| ID | ParentID | Name |  Url | 
+-----+----------+------------+-------------+ 
| 1 |  0 | Categories | categories | 
| 34 |  1 | Movies  | movies  | 
| 281 |  34 | Star Wars | star-wars | 
| 33 |  1 | Books  | a-good-book | 
+-----+----------+------------+-------------+ 

Was ich will, ist zu tun, dass ich rekursiv in der Lage sein, durch alle Felder zu gehen, und nach dem ParentID, speichern alle möglichen url Kombinationen . So

, aus der Tabelle oben, ich möchte die folgende Ausgabe erhalten:

mysite.com/categories 
mysite.com/categories/movies 
mysite.com/categories/movies/star-wars 
mysite.com/categories/books 
mysite.com/categories/books/a-good-book 

Ich habe angefangen, einen CTE schreiben, die aussehen wie folgt aus:

WITH CategoriesCTE AS 
    (
    SELECT 
     Name, 
     Url, 
     ParentID, 
     ID 
    FROM myDB 
    WHERE ParentID = 1 

    UNION ALL 

    SELECT 
     a.Name, 
     a.Url, 
     a.ParentID, 
     a.ID 
    FROM myDB.a 
    INNER JOIN CategoriesCTE s on a.ParentID = s.ID 
) 

    SELECT * FROM CategoriesCTE 

Das Ding ist, Dieser Datenbankanruf speichert alles flach. Was ich tun müsste, ist, dass für jeden Schritt alle URLs gespeichert werden und dann für jede ID die URL entsprechend der ParentID gespeichert wird. Im Moment ist es natürlich nicht formatiert ist, aber meine Ausgabe ist rundweg so etwas wie:

mysite.com/categories 
mysite.com/movies 
mysite.com/star-wars 
mysite.com/a-good-book 

, die eine Menge defekte Links erstellt. Gibt es eine Möglichkeit, eine Aktion/Auswahl für jeden rekursiven Schritt auszuführen? Wie soll ich dieses Problem angehen?

+1

Ist Ihre Datenstruktur korrekt? Die URL nach Kategorien hat Bücher, bevor sie eine bestimmte hat, aber in der ersten Tabelle, die Sie beschreiben, würde sie basierend auf der Beziehung direkt in Kategorien gehen? – Leonidas199x

Antwort

0

Sehen Sie, was Sie davon halten ...

IF OBJECT_ID('tempdb..#SomeTable', 'U') IS NOT NULL 
DROP TABLE #SomeTable; 

CREATE TABLE #SomeTable (
    ID INT NOT NULL, 
    ParentID INT NOT NULL, 
    FolderName VARCHAR(20) NOT NULL, 
    UrlPath VARCHAR(8000) NULL 
    ); 
INSERT #SomeTable (ID, ParentID, FolderName) VALUES 
    (1 , 0 , 'categories'), 
    (34 , 1 , 'movies'), 
    (281, 34, 'star-wars'), 
    (33 , 1 , 'a-good-book'); 

-- SELECT * FROM #SomeTable st; 

WITH 
    cte_Categories AS (
     SELECT 
      SitePath = CAST(CONCAT('mysite.com/', st.FolderName) AS VARCHAR(8000)), 
      st.ID, 
      NodeLevel = 1 
     FROM 
      #SomeTable st 
     WHERE 
      st.ParentID = 0 
     UNION ALL 
     SELECT 
      SitePath = CAST(CONCAT(c.SitePath, '/', st.FolderName) AS VARCHAR(8000)), 
      st.ID, 
      nodeLevel = c.NodeLevel + 1 
     FROM 
      cte_Categories c 
      JOIN #SomeTable st 
       ON c.ID = st.ParentID 
     ) 
SELECT 
    c.SitePath, 
    c.ID, 
    c.NodeLevel 
FROM 
    cte_Categories c; 
1

einige neue Felder zu Ihrem rekursiven CTE hinzufügen zu verfolgen:

  1. Rekursionstiefen (so können Sie den Datensatz mit der größten Tiefe
  2. Der Weg, der durch jede Iteration gebaut werden finden, indem die neueste Wert zu verketten.
  3. der Ausgangspunkt der Rekursion, so dass Sie wissen, was Rekord Sie

mit gestartet
WITH CategoriesCTE AS 
    (
    SELECT Name, Url, ParentID, ID, 1 as depth, CAST(url as VARCHAR(500)) as path, url as startingpoint 
    FROM myDB 
    WHERE ParentID = 1 
    UNION ALL 

    SELECT a.Name, a.Url, a.ParentID, a.ID, s.depth + 1, a.url + s.path, s.url 
    FROM myDB.a 
    INNER JOIN CategoriesCTE s on a.ParentID = s.ID 
) 

    SELECT * FROM CategoriesCTE 
Verwandte Themen