2017-02-09 130 views
1

我正在研究SQL Server 2008.我相信我Q的答案在於遞歸CTE,但任何解決方案都將不勝感激。SQL組與遞歸CTE

在sam_DB.dbo.example見下表,其中PID是不是空它鏈接回到一個ID

ID  | PID 
    ------ | ------ 
    1  | NULL 
    2  | 1  
    3  | 2  
    4  | 3  
    5  | NULL 
    6  | 5  
    7  | 6  
    8  | NULL 
    9  | NULL 
    10  | 9  

我希望我的輸出有一個新的領域(CID)標識的每個記錄作爲一個羣體的一部分,從PID到ID的連鎖鏈如下所示。

ID  | PID | CID 
    ------ | ------ | ------ 
    1  | NULL | 1  
    2  | 1  | 1  
    3  | 2  | 1  
    4  | 3  | 1  
    5  | NULL | 2  
    6  | 5  | 2  
    7  | 6  | 2  
    8  | NULL | 3  
    9  | NULL | 4  
    10  | 9  | 4  

回答

0

,你必須使用常見的文本表達隨着ROW_NUMBER窗口功能

CREATE TABLE #TblTemp(ID int,PID int) 


INSERT INTO #TblTemp(ID ,PID) VALUES (1,NULL),(2,1),(3,1),(4,3),(5,NULL),(6,5),(7,6),(8,NULL),(9,NULL),(10,9) 


;WITH CTE (ID, PID, CID) AS (

    SELECT ID, PID, ROW_NUMBER() OVER(ORDER BY ID) RN 
    FROM #TBLTEMP 
    WHERE PID IS NULL 

    UNION ALL 

    SELECT T.ID, T.PID, C.CID 
    FROM CTE C 
    INNER JOIN #TBLTEMP T 
    ON T.PID = C.ID 
) 
SELECT * 
FROM CTE 
ORDER BY ID 
1

你是對的,你需要一個CTE。

您需要定義查詢的第一部分,選擇頂層的記錄(即那些沒有父):

select ID, PID, ID 
from @t 
where PID is null 

然後,對於每一行加入到得到的CTE(即第一全部用於由上述查詢返回的那些記錄,然後針對由查詢的第二部分添加的每個新行再次添加,對於每個添加重複,直到不添加新的添加爲止),應該添加來自源表的父記錄的所有記錄匹配先前添加的行的ID。

select t.ID, t.PID, c.CID 
from cte c 
inner join @t t 
on t.PID = c.ID 

除了這個邏輯,只有其他的事情要注意的是,第一個表達式的CID列將記錄的ID,而對於所花費的父記錄的CID的第二個表達式返回的記錄。

全碼

--set up the demo data 
declare @t table (ID int not null, PID int null) 
insert @t 
values (1, null) 
, (2,1) 
, (3,2) 
, (4,3) 
, (5,null) 
, (6,5) 
, (7,6) 
, (8,null) 
, (9,null) 
, (10,9) 

--actual demo 
;with cte (ID, PID, CID) as (

    --select out top most (ancestor) records; setting CID to ID (since they're the oldest ancestor in their own chain, given they don't have parents) 
    select ID, PID, ID 
    from @t 
    where PID is null 

    union all 

    --select each record that is a child of the record we previously selected, holding the ancestor as the parent record's ancestor 
    select t.ID, t.PID, c.CID 
    from cte c 
    inner join @t t 
    on t.PID = c.ID 
) 
select * 
from CTE 
order by ID