2017-02-09 171 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