带有递归CTE的SQL组

问题描述 投票:1回答:3

我正在研究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     
sql sql-server sql-server-2008 recursion
3个回答
0
投票

你必须使用Common文本表达式和Row_Number Window函数

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与之前添加的行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

0
投票

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

声明@t table(item varchar(2),tr int null,rc int null)insert @t select'a',1,9 - no links'a' - 是group parent insert @t select'b',2 ,1 - 链接到'a'插入@t select'c',3,2 - 链接到'b'插入@t选择'd',4,3 - 链接到'd'插入@t选择' e',6,7 - 没有链接'e' - 是一个不同的组插入@t select'f',8,2 - 链接到'c'

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

;使用cte as(选择grn = s.item,gid = s.tr,s.item,s.tr,rc_New = t.tr,rc_Old = s.rc来自@ts left join @tt on t.tr = s .rc其中(t.tr为NULL或s.rc为NULL)union cte c join中选择c.grn,c.gid,s.item,s.tr,rc_New = s.rc,rc_Old = s.rc @ts on s.rc = c.tr,其中s.rc不为NULL)从cte order中选择*为2,3

选项(MAXRECURSION 32767,FAST 100)

© www.soinside.com 2019 - 2024. All rights reserved.