带有递归CTE的SQL组

时间:2017-02-09 20:56:09

标签: sql sql-server sql-server-2008 recursion

我正在研究SQL Server 2008.我相信我的Q的答案在于递归CTE,但任何解决方案都会非常感激。

在下面的sam_DB.dbo.example表中,PID不为null,它会链接回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     

3 个答案:

答案 0 :(得分:1)

你是正确的,你需要一个CTE。

您需要定义查询的第一部分以选择顶级记录(即没有父级的记录):

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

然后,对于添加到生成的CTE的每一行(即首先对于上述查询返回的那些记录,然后再次为查询的第二部分添加的每个新行,重复每次添加直到没有新增加你应该添加来自源表的所有记录,其父id与先前添加的行的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

答案 1 :(得分: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

答案 2 :(得分:0)

我将发布一些简单的示例 -显示如何为父/子组的错误链接或损坏的块创建递归分组

声明@t表(item varchar(2),tr int null,rc int null) 插入@t选择'a',1,9-无链接'a'-是组父级 插入@t选择'b',2,1-链接到'a' 插入@t选择'c',3,2-链接到'b' 插入@t选择'd',4,3-链接到'd' 插入@t选择'e',6,7-无链接'e'-是不同的组 插入@t选择'f',8,2-链接到'c'

-基于父项名称的grn-group名称; -基于父项id的gid-group名称; -tr-transactionID; rc-recursiveID; -使用的rc_New-new recursiveID; rc_Old-原始递归ID

;使用cte作为 ( 从@t s中选择grn = s.item,gid = s.tr,s.item,s.tr,rc_New = t.tr,rc_Old = s.rc t.tr = s.rc上的左连接@t t,其中(t.tr为NULL或s.rc为NULL) 全部合并 选择c.grn,c.gid,s.item,s.tr,rc_New = s.rc,rc_Old = s.rc 来自cte c join @t s s.rc = c.tr,其中s.rc不为NULL ) 从CTE订单中选择*,按2,3

选项(MAXRECURSION 32767,快速100)

相关问题