递归地从数据库获取嵌套URL

时间:2017-08-30 15:16:55

标签: sql sql-server common-table-expression

我有一个使用嵌套URL构建的数据库表,使用ParentID和ID来判断哪个URL属于哪里。

表结构如下所示:

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

我想要做的是我希望能够递归遍历所有字段,并根据ParentID保存所有可能的url组合。

因此,从上表中,我想获得以下输出:

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

我开始写CTE,看起来像这样:

  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

事实是,这个数据库调用可以保存所有内容。我需要做的是,对于每个步骤,保存所有URL,然后为每个ID,根据ParentID保存url。现在它当然没有格式化,但我的输出完全像:

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

这会产生很多破碎的链接。 是否有某种方法可以为每个递归步骤执行操作/选择?我该如何处理这个问题呢?

2 个答案:

答案 0 :(得分:1)

在您的递归CTE中添加一些新字段以跟踪:

  1. 递归深度(这样您就可以找到深度最大的记录
  2. 通过将最新值连接到每次迭代将构建的路径。
  3. 递归的起点,以便您知道以
  4. 开头的记录
      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
    

答案 1 :(得分:0)

看看你对此的看法......

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;