2

SQL ServerのWithコマンド(CTE)を使用して再帰を実現できます。

WITH MyCTE(ParentID,ID,Name,Level)
AS
(
SELECT ManagerID AS ParentID, UserID AS ID, UserName AS Name, 0 AS Level 
FROM USERS U       
WHERE U.ManagerID IS NULL

UNION ALL

SELECT U.ManagerID AS ParentID, U.UserID AS ID, U.UserName AS Name, H.Level+1 AS Level
FROM USERS U
INNER JOIN MyCTE H ON H.ID = U.ManagerID
)

SELECT ParentID,ID FROM MyCTE

戻り値

ParentID    ID
NULL        1
1           2
1           3
2           4

私が達成したいのは、この結果セットを逆にすることです。つまり、ルートノードと最も深い子ノードを次のように反転します。

ParentID    ID
NULL        4
4           2
2           1
3           1

パラメータを使用して再帰順序を決定するなど、プログラムでこれを実装する方法(できればCTEを使用する方法)を理解できませんでした。助けていただければ幸いです。

編集 :

これを少し変更して、最初のCTEの結果を一時テーブルに挿入し、別の再帰を使用して順序を逆にします( "WHERE T.ID =(SELECT MAX(ID)FROM @tmp)"は実際の状況では機能しないことを知っています。また、「レベル」列を使用して最も深いノードを特定する必要があります。この例では、これを単純化しようとしました)、

 INSERT INTO @tmp
 SELECT ParentID,ID,Level FROM MyCTE
 WITH MyCTE2(ParentID,ID,Level)
 AS
 (
 SELECT NULL AS ParentID, ID AS ID, 0 AS Level FROM @tmp T 
 WHERE T.ID = (SELECT MAX(ID) FROM @tmp)

 UNION ALL

 SELECT R2.ID AS ParentID, T.ParentID AS ID, R2.Level+1 FROM @tmp T
 INNER JOIN MyCTE2 R2 ON R2.ID = T.ID
 WHERE T.ParentID IS NOT NULL
 )

元の結果(1,3ペアを削除)

ParentID   ID   Level
  NULL      1     0
    1       2     1
    2       4     2

結果が逆になり、

ParentID   ID   Level
  NULL      4     0
    4       2     1
    2       1     2

編集2:

私はこのようなことをしました、

SELECT TTT.ParentID,TTT.ID,TTT.Level FROM
(
SELECT ParentID,ID,Level FROM MyCTE2
UNION ALL
SELECT TT.ID AS ParentID,TT.ParentID AS ID,(SELECT Level+1 FROM @tmp WHERE ID=TT.ID) 
AS  Level  FROM
(
SELECT ID FROM @tmp
EXCEPT
SELECT ID FROM MyCTE2
)T INNER JOIN @tmp TT ON TT.ID = T.ID
)TTT
ORDER BY TTT.Level

与える、

ParentID    ID  Level
NULL        4   0
4           2   1
2           1   2
3           1   2

これにはエラーが含まれている可能性がありますが、まだわかりませんが、ペア(3,1)がレベル2で正しいことを確認するために表示したかっただけですか?かなり前からこれについて考えていたので、私はいくつかのばかげた間違いをするかもしれません。

4

1 に答える 1

4

サンプルデータ

declare @T table
(
  ParentID int,
  ID int
)

insert into @T values
(NULL,        1),
(1   ,        2),
(1   ,        3),
(2   ,        4)

ルートからの再帰:

;with C as
(
  select ParentID, ID
  from @T
  where ParentID is null
  union all
  select T.ParentID, T.ID
  from @T as T
    inner join C
      on T.ParentID = C.ID
)
select *
from C

結果

ParentID    ID
----------- -----------
NULL        1
1           2
1           3
2           4

葉からの再帰:

;with C as
(
  select null as PParentID, ID, ParentID
  from @T
  where ID not in (select ParentID 
                   from @T 
                   where ParentID is not null)
  union all
  select C.ID, T.ID, T.ParentID 
  from @T as T
    inner join C
      on T.ID = C.ParentID 
)
select distinct
       PParentID as ParentID,
       ID
from C

結果:

ParentID    ID
----------- -----------
NULL        3
NULL        4
4           2
2           1
3           1

ブランチが多数ある場合は、マージとして重複する行があります。を使用distinctすると、その面倒を見ることができます。

レベルを正しくするには、最初にレベルを上から下に計算する必要があります。これをテーブル変数(または一時テーブル)に格納し、それをleaf->root再帰のソースとして使用します。

-- Primary key and unique is in there to get the indexes used in the recursion  
declare @T2 table
(
  ParentID int,
  ID int,
  Level int,
  primary key (ID),
  unique(ParentID, ID)
)

;with C as
(
  select ParentID, ID, 0 as Level
  from @T
  where ParentID is null
  union all
  select T.ParentID, T.ID, Level + 1
  from @T as T
    inner join C
      on T.ParentID = C.ID
)
insert into @T2
select ParentID, ID, Level
from C

;with C as
(
  select null as PParentID, ID, ParentID, Level
  from @T2
  where ID not in (select ParentID 
                   from @T2 
                   where ParentID is not null)
  union all
  select C.ID, T.ID, T.ParentID, T.Level
  from @T2 as T
    inner join C
      on T.ID = C.ParentID 
)
select distinct
       PParentID as ParentID,
       ID,
       max(Level) over() - Level as level
from C

結果:

ParentID    ID          level
----------- ----------- -----------
NULL        3           1
NULL        4           0
2           1           2
3           1           2
4           2           1

@ T2をマルチCTEクエリに置き換えることは可能ですが、非常に悪い考えです。最初にCTEが再帰ごとに再構築されるため、パフォーマンスが低下します。少なくともそれは何が起こっているかについての私の推測ですが、それは速くないと私を信じています。

于 2012-04-10T20:02:31.067 に答える