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

したがって、基本的に親子階層テーブルがありますが、1 つの微妙な違いがあります。それぞれの子は、複数の親を持つ可能性があります。親子レコードを返す CTE の作成について、多くのブログ記事と StackOverflow 投稿を調査しましたが、それらは子のすべての親を返すわけではなく、最初に見つかったものだけを返します。

私が試した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 から始まるすべての親子レコードを検索しますが、2 つの親があるにもかかわらず、アイテム ID:900 の親を 1 つだけ検索します。

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 に答える