4

我正在 SQL Server 中试验 CTE,但在使以下场景正常工作时已经走到了死胡同。我有一个类似于这样的层次结构表:

Node(ID:439)
  Node(ID:123)
    Node(ID:900)        
  Node(ID:56)
    Node(ID:900)

预期成绩:

NodeID ParentNodeID
439    0
123    439
900    123
56     439
900    56

所以基本上我们有一个父子层次表,有一个细微的区别。每个孩子可能有不止一个父母。我研究了许多博客文章和 StackOverflow 帖子,关于创建返回父子记录的 CTE,但它们并没有返回孩子的所有父母,只是它找到的第一个。

这是我尝试的示例 CTE:

WITH Hierarchy(NodeID, ParentNodeID)
AS
(
    SELECT 
        T1.NodeID,
          T1.ParentNodeID
    FROM
        ParentChildTable T1
    WHERE
        T1.NodeID = 439

    UNION ALL
    SELECT 
        T1.NodeID,
        T1.ParentNodeID
    FROM
        Heirarchy T1
        INNER JOIN Heirarchy TH ON TH.NodeID = T1.ParentNodeID
)

(注:为保护隐私,上述 CTE 中的表名和列名已从原始更改。)

上面的 CTE 工作正常,它找到了从 ID:439 开始的所有父子记录,但它只找到了 ID:900 的一个父项,即使它有两个父项。

有人可以让我知道这是否可以使用 CTE,或者是否有另一种 SQL 方法可以做到这一点?

干杯。贾斯。

4

2 回答 2

5

一旦我更正了 CTE 中的语法错误,这对我来说似乎可以正常工作:

create table #ParentChildTable 
(nodeID int not null
,parentNodeID int not null
)

insert #ParentChildTable 
select 900,56
union all select 900,123
union all select 123,439
union all select 56,439
union all select 439,0

;WITH Heirarchy
AS
(
    SELECT 
        T1.NodeID,
          T1.ParentNodeID
    FROM
        #ParentChildTable T1
    WHERE
        T1.NodeID = 439

    UNION ALL
    SELECT 
        T1.NodeID,
        T1.ParentNodeID
    FROM
        #ParentChildTable T1
        INNER JOIN Heirarchy TH ON TH.NodeID = T1.ParentNodeID
)
select *
from Heirarchy

返回结果:

NodeID      ParentNodeID
----------- ------------
439         0
123         439
56          439
900         56
900         123
于 2009-03-20T10:54:35.630 回答
1

这是我用来寻找解决方案的链接..

http://wiki.lessthandot.com/index.php/Using_Common_Table_Expressions_for_Parent-Child_Relationships

编辑 - @Pshimo - 谢谢。这是链接中的指南。

使用 SQL 2005 虽然这是一个梦想。假设您有以下示例数据:

declare @test table (bunchof uniqueidentifier default newid(), columns uniqueidentifier default newid(), Id int, ParentID int)

insert @test (Id, ParentId)
select 1, null
union all select 5, 1
union all select 15, 2
union all select 16, 5
union all select 27, 16

并且您想获取 1 的所有子行(因此 ItemId 5、16、27)

 declare @parentId int
    set @parentId = 1

    ;--last statement MUST be semicolon-terminated to use a CTE
    with CTE (bunchof, columns, Id, ParentId) as
    (
        select bunchof, columns, Id, ParentId
        from @test
        where ParentId = @parentId
        union all
        select a.bunchof, a.columns, a.Id, a.ParentId
        from @test as a
        inner join CTE as b on a.ParentId = b.Id
    )
    select * from CTE

如果你想包括父母:

declare @Id int
set @Id = 1

;--last statement MUST be semicolon-terminated to use a CTE
with CTE (bunchof, columns, Id, ParentId) as
(
    select bunchof, columns, Id, ParentId
    from @test
    where Id = @Id
    union all
    select a.bunchof, a.columns, a.Id, a.ParentId
    from @test as a
    inner join CTE as b on a.ParentId = b.Id
)
select * from CTE

如果您喜欢这种情况,您也可以在层次结构中选择深度:

declare @Id int
set @Id = 1

;--last statement MUST be semicolon-terminated to use a CTE
with CTE (bunchof, columns, Id, ParentId, Depth) as
(
    select bunchof, columns, Id, ParentId, 0
    from @test
    where Id = @Id
    union all
    select a.bunchof, a.columns, a.Id, a.ParentId, b.Depth + 1
    from @test as a
    inner join CTE as b on a.ParentId = b.Id
)
select * from CTE

如您所见,您在这里所做的是首先选择您的初始记录集,其中包含父 ID 参数的所有子行。然后,您可以联合到另一个连接到 CTE 本身的查询,以获取孩子的孩子(和他们的孙辈,等等,直到您到达最后一个后代行。重要的是要注意默认递归限制为 100,所以请支付使用这些时要注意层次结构的深度。您可以使用 OPTION (MAXRECURSION) 更改递归限制

 WITH CTE AS (
    ...
    )
    SELECT * FROM CTE OPTION (MAXRECURSION 1000)
于 2013-02-08T01:33:24.747 回答