2

我知道这是一个常见的“递归查找”类型的问题,并且有很多关于 SO,但我找不到解决我的特定问题的答案。这是我需要使用从客户那里继承的数据来解决的问题。

考虑下表示例(实际数据的简化版本):

ancestor_page_id parent_page_id page_id page_name 
---------------- -------------- ------- ---------
NULL             1              3       ROOT A
NULL             3              4       CHILD A
NULL             4              5       SUB CHILD A
NULL             4              6       SUB CHILD B
NULL             5              7       SUB SUB CHILD A
NULL             2              8       ROOT B
NULL             8              9       CHILD B
NULL             9              10      SUB CHILD C
NULL             9              11      SUB CHILD D
NULL             10             12      SUB SUB CHILD B

我如何将其放入表格中:

ancestor_page_id parent_page_id page_id page_name 
---------------- -------------- ------- ---------
1                1              3       ROOT A
1                3              4       CHILD A
1                4              5       SUB CHILD A
1                4              6       SUB CHILD B
1                5              7       SUB SUB CHILD A
2                2              8       ROOT B
2                8              9       CHILD B
2                9              10      SUB CHILD C
2                9              11      SUB CHILD D
2                10             12      SUB SUB CHILD B

其中ancestor_page_id是祖传parent_page_id值。

我知道parent_page_id1并且2应该有记录,但它们不存在(没有 FK 约束)。

我希望这是有道理的。请帮忙!

4

2 回答 2

1

如果没有全文索引,通过标签搜索将非常昂贵。我们不必依赖它。

DECLARE @your_table TABLE (
    ancestor_page_id INT NULL
    , parent_page_id INT NOT NULL
    , page_id INT NOT NULL
    , page_name VARCHAR(255) NOT NULL
)

INSERT INTO @your_table (ancestor_page_id, parent_page_id, page_id, page_name)
VALUES  (NULL, 1, 3, 'ROOT A')
    , (NULL, 3, 4, 'CHILD A')
    , (NULL, 4, 5, 'SUB CHILD A')
    , (NULL, 4, 6, 'SUB CHILD B')
    , (NULL, 5, 7, 'SUB SUB CHILD A')
    , (NULL, 2, 8, 'ROOT B')
    , (NULL, 8, 9, 'CHILD B')
    , (NULL, 9, 10, 'SUB CHILD C')
    , (NULL, 9, 11, 'SUB CHILD D')
    , (NULL, 10, 21, 'SUB SUB CHILD B')
;

WITH recursive_cte
AS (
    -- find roots
    SELECT T1.parent_page_id ancestor_page_id, T1.parent_page_id, T1.page_id, T1.page_name
    FROM @your_table T1
        -- look for any records which have no parents, i.e. roots/trunks
        LEFT JOIN @your_table T2 ON T1.parent_page_id = T2.page_id
    WHERE T2.page_id IS NULL

    UNION ALL

    -- now find all children down each branch, passing the root value intact
    SELECT T4.ancestor_page_id, T3.parent_page_id, T3.page_id, T3.page_name
    FROM @your_table T3
        INNER JOIN recursive_cte T4 ON T3.parent_page_id = T4.page_id
)
SELECT *
FROM recursive_cte
ORDER BY page_id ASC
于 2013-08-30T10:26:54.507 回答
0

这是否提供了所需的输出?

DECLARE @TABLE TABLE
(
    ancestor_page_id INT NULL,
    parent_page_id INT NOT NULL,
    page_id INT NOT NULL,
    page_name VARCHAR(50) NOT NULL
);
INSERT INTO @TABLE
VALUES
(NULL, 1,  3, 'ROOT A'),
(NULL, 3,  4, 'CHILD A'),
(NULL, 4,  5, 'SUB CHILD A'),
(NULL, 4,  6, 'SUB CHILD B'),
(NULL, 5,  7, 'SUB SUB CHILD A'),
(NULL, 2,  8, 'ROOT B'),
(NULL, 8,  9, 'CHILD B'),
(NULL, 9,  10, 'SUB CHILD C'),
(NULL, 9,  11, 'SUB CHILD D'),
(NULL, 10, 12, 'SUB SUB CHILD B');

WITH CTE(ancestor_page_id, parent_page_id, page_id, page_name)
AS
(
    SELECT
        parent_page_id AS ancestor_page_id, 
        parent_page_id, 
        page_id, 
        page_name
    FROM
        @TABLE 
    WHERE
        page_name LIKE 'ROOT%' -- An assumption for the anchor?

    UNION ALL

    SELECT
        CTE.ancestor_page_id,
        T.parent_page_id, 
        T.page_id, 
        T.page_name     
    FROM
        CTE
        INNER JOIN @TABLE AS T
        ON T.parent_page_id = CTE.page_id    
)

SELECT * FROM CTE
ORDER BY ancestor_page_id, parent_page_id, page_id
于 2013-08-30T10:19:37.253 回答