SQL Parent 的服务器 Make Tracks 或 Path 有很多 child

SQL Server Make Tracks or Path of Parent has many child

我有一个 Activity table :

ActivityID       ActivityName
-----------------------------
 1                A1
 2                A2
 3                A3
 4                A4
 5                A5
 6                A6
 7                A7
 8                A8
 9                A9
 10               A10

并在另一个 table 中将其与 parent child 关系关联为:

ParentActivityID     ChildActivityID
-------------------------------------
 1                     2
 1                     3
 2                     4
 2                     5
 3                     6 
 4                     7
 5                     7
 6                     8
 7                     9
 8                     9
 9                     10

我想写一个 SQL 查询,它将根据一个 parentActivity 中有多少 childActivity 进行跟踪,例如:

ActivityID    TrackGroup
-------------------------
 1             1
 2             1
 4             1
 7             1
 9             1
 10            1
 1             2
 2             2
 5             2
 7             2
 9             2
 10            2
 1             3
 3             3
 6             3
 8             3
 9             3
 10            3

使用 sql 服务器 2008 r

根据您的 table 大小,这可能是地球上最慢的查询,但它确实满足了您的要求,我无法真正测试性能。

但是创建测试数据。

CREATE TABLE Activity
    ([ActivityID] int, [ActivityName] varchar(3))
;
INSERT INTO Activity
    ([ActivityID], [ActivityName])
VALUES
    (1, 'A1'),    (2, 'A2'),    (3, 'A3'),    (4, 'A4'),    (5, 'A5'),
    (6, 'A6'),    (7, 'A7'),    (8, 'A8'),    (9, 'A9'),    (10, 'A10')
;
CREATE TABLE RelatedActivity
    ([ParentActivityID] int, [ChildActivityID] int)
;
INSERT INTO RelatedActivity
    ([ParentActivityID], [ChildActivityID])
VALUES
    (1, 2),    (1, 3),    (2, 4),    (2, 5),    (3, 6),    (4, 7),
    (5, 7),    (6, 8),    (7, 9),    (8, 9),    (9, 10)
;

只是假设您可能 运行 这为 1 activity 所以我创建了一个变量并将其设置为第一个 ActivityID

DECLARE @ActivityID INT = 1

然后我使用递归 cte 来获取层次结构。我添加了一个 "Path" 字段,它只是将当前 ID 与以前的 ID 连接起来。

然后使用 SQL 2008 中的 ROW_NUMBER 函数并按 PATH 排序,我可以得到下一个 PATH.

然后我可以比较当前路径的LEN和下一条路径的LEN,看看接下来是否有新的路径开始,如果有则给我当前路径。或者如果下一个 PATH 是 NULL 也得到它。

然后我使用字符串拆分函数将剩余的路径转换为行。

--Get hierarchy
;WITH cte AS 
(
    SELECT  [ActivityID], NULL ParentActivityID, CAST([ActivityID] AS VARCHAR(255)) [Path] 
    FROM    Activity WHERE [ActivityID] = @ActivityID
    UNION ALL
    SELECT  ra.[ChildActivityID], ra.[ParentActivityID], CAST([Path] + '.' + CAST(ra.[ChildActivityID] AS VARCHAR(255)) AS VARCHAR(255))
    FROM    Activity a
    JOIN    RelatedActivity ra ON a.[ActivityID] = ra.[ChildActivityID]
    JOIN    cte ON ra.[ParentActivityID] = cte.[ActivityID]
)

SELECT *, ROW_NUMBER() OVER (ORDER BY [Path]) Rn 
INTO #tempHierarchy 
FROM cte 

SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) AS ActivityID,
       Rn AS TrackGroup
FROM
(
    SELECT  ROW_NUMBER() OVER (ORDER BY [Path]) Rn, 
            CAST('<XMLRoot><RowData>' + REPLACE([Path],'.','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
    FROM
        #tempHierarchy t1
        LEFT JOIN (SELECT [Path] [Next], ROW_NUMBER() OVER (ORDER BY [Path]) - 1 Rn  FROM #tempHierarchy) t2 ON t1.Rn = t2.Rn
    WHERE
        [NEXT] IS NULL OR LEN([Next]) < LEN([Path])
)t
CROSS APPLY x.nodes('/XMLRoot/RowData')m(n) 

SQL Fiddle