1

私が見つけることができる再帰的な CTE の例はすべて、本質的に同じシナリオを使用しています。それらはすべて、組織図を上または下に移動します。私の CTE は、1 人の従業員に 1 人のマネージャーがいるような、1 対 1 の親子関係に適していますが、子が複数の親を持つことができるテーブルがあります。私が欲しいのは、1 つの子に由来する親 ID の明確なリストです。

詳細に興味がある場合は、MS Project ファイル内の特定のタスクの先行タスクを再帰しています。特定のマイルストーンから始めて、そのマイルストーンに影響を与えている可能性のある前任者を見つけるために、ファイルの先頭までトレースしたいと考えています。ご存じかもしれませんが、タスクは複数の先行タスクを持つことができます。

私の関係は次のようになります。

tblタスク

child    parent
3        1
16       1
25       1
25       3
25       16
26       1
26       3
27       25
27       26

ここに私のCTEがあります:

;WITH ProjectTrace(Task)
AS
(
    -- Anchor member definition (This is task 27)
    SELECT t.parent AS Task
    FROM #tblTasks t
    WHERE t.child = 27

    UNION ALL

    -- Recursive member definition (This is everything that hooks into 27 via predecessors)
    SELECT t.parent AS Task
    FROM #tblTasks t
    INNER JOIN ProjectTrace trace
        ON t.child = trace.Task
)
SELECT * FROM ProjectTrace ORDER BY Task

タスク #27 をクエリに提供し、結果セットで 1,3,16,25,26 のみを取得したい。ただし、再帰の仕組みにより、結果セットは次のようになります。

Task
1
1
1
1
1
3
3
16
25
26

関係を見れば、それは理にかなっていると思います。select a end を select distinct に変更することはいつでもできますが、プロジェクトに深く入り込むと (タスク番号 500 など)、何百万ものレコードが返されます。

私は何を間違っているのでしょうか?

4

2 に答える 2

0

distinctはこれを行う良い方法だと思います。反復挿入ソリューションを確認することもできます。

declare @Temp table(Task int primary key)

insert into @Temp
select distinct parent from Table1 where child = 27

while 1 = 1
begin
    insert into @Temp
    select distinct T.parent
    from Table1 as T
    where
        exists (select * from @Temp as TT where TT.Task = T.child) and
        not exists (select * from @Temp as TT where TT.Task = T.parent)

    if @@rowcount = 0 break
end

select * from @Temp

速くなるかどうかわからないので、自分で確認してください。

于 2013-10-24T19:17:35.477 に答える
0

よりも優れたパフォーマンスのオプションはないと思いますDISTINCT

LEFT JOINtrace.Task を制限するためにa を使用することはIS NULLできませんGROUP BY。進むべき道だと思いますDISTINCT

于 2013-10-24T19:23:46.613 に答える