2013-08-30 54 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