2013-08-30 52 views
2

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

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

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_id12应该有记录,但它们不存在(没有FK约束)。

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

+0

所以,你想在ancestor_page_id列中设置整个序列的第一个“父”? – gotqn

+0

是的,如果我明白你的意思是“序列”。因此,例如'SUB SUB CHILD A'具有'parent_page_id''5'('SUB CHILD A''),其具有'parent_page_id''4'('CHILD_A'),其具有'parent_page_id''3'('ROOT A'),它具有'parent_page_id''1',这就是'ancestor_page_id'变为 – lozz

回答

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 
+0

这是为我“观看”图片的非常奇怪的方式。但是,同时,明确的解决方案。 +1 – gotqn

+0

谢谢@xerxes。工作过一种享受! – lozz

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 
+0

谢谢@Meff。但是我没有尝试你的解决方案,因为我不想在查询中使用'page_name'。 @xerxes解决方案为我工作 – lozz