24

次のように2つのテーブルがあります

テーブルPerson

  Id   Name
   1    A
   2    B
   3    C
   4    D
   5    E

テーブルRelationHierarchy

ParentId   ChildId
   2         1
   3         2
   4         3

これにより、ツリーのような構造が形成されます

          D
          |
          C
          |
          B
          |
          A

ParentId と ChildId は Person テーブルの Id 列の外部キーです

トップレベルの親、つまりルートをフェッチできる SQL を記述する必要があります。これを達成するのに役立つSQLを誰かが提案できますか

4

9 に答える 9

34

再帰 CTEを使用してそれを実現できます。

DECLARE @childID INT 
SET @childID  = 1 --chield to search

;WITH RCTE AS
(
    SELECT *, 1 AS Lvl FROM RelationHierarchy 
    WHERE ChildID = @childID

    UNION ALL

    SELECT rh.*, Lvl+1 AS Lvl FROM dbo.RelationHierarchy rh
    INNER JOIN RCTE rc ON rh.CHildId = rc.ParentId
)
SELECT TOP 1 id, Name
FROM RCTE r
inner JOIN dbo.Person p ON p.id = r.ParentId
ORDER BY lvl DESC

SQLFiddle デモ

編集- すべての子の最上位の親に対する更新されたリクエスト:

;WITH RCTE AS
(
    SELECT  ParentId, ChildId, 1 AS Lvl FROM RelationHierarchy 

    UNION ALL

    SELECT rh.ParentId, rc.ChildId, Lvl+1 AS Lvl 
    FROM dbo.RelationHierarchy rh
    INNER JOIN RCTE rc ON rh.ChildId = rc.ParentId
)
,CTE_RN AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY r.ChildID ORDER BY r.Lvl DESC) RN
    FROM RCTE r

)
SELECT r.ChildId, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM CTE_RN r
INNER JOIN dbo.Person pp ON pp.id = r.ParentId
INNER JOIN dbo.Person pc ON pc.id = r.ChildId
WHERE RN =1

SQLFiddle デモ

EDIT2 - すべての人が最後に JOINS を少し変更するには:

SELECT pc.Id AS ChildID, pc.Name AS ChildName, r.ParentId, pp.Name AS ParentName
FROM dbo.Person pc 
LEFT JOIN CTE_RN r ON pc.id = r.CHildId AND  RN =1
LEFT JOIN dbo.Person pp ON pp.id = r.ParentId

SQLFiddle デモ

于 2013-07-16T13:11:40.790 に答える
10

このパターンを使用して、階層内のアイテムをアイテムのルート ノードに関連付けました。

ルートノードの値を各行に追加された追加の列として維持する階層を本質的に再帰します。お役に立てれば。

with allRows as (
    select ItemId, ItemName, ItemId [RootId],ItemName [RootName] 
    from parentChildTable
    where ParentItemId is null
    union all
    select a1.ItemId,a1.ItemName,a2.[RootId],a2.[RootName]
    from parentChildTable a1
    join allRows a2 on a2.ItemId = a1.ParentItemId
)   

select * from allRows
于 2013-10-31T12:12:27.080 に答える
3

これを試して。

再帰 CTE は人を見つけ、親が見つからなくなるまで階層を上っていきます。

-- This CTE will find the ancestors along with a measure of how far up
-- the hierarchy each ancestor is from the selected person.
with ancestor as (
  select ParentId as AncestorId, 0 as distance
  from RelationHierarchy
  where CHildId = ?

  union all

  select h.ParentId, a.distance + 1
  from ancestor a inner join RelationHierarchy rh on a.AncestorId = rh.ChildId
)
select AncestorId
from ancestor
where distance = (select max(distance) from ancestor)
于 2013-07-16T13:15:59.163 に答える
0

これを試してください:

    ID、名前を選択
    pさんより
    存在しない場所
    (
    1を選択
    関係階層から r
    ここで、r.childid = p.id
    )
    そして存在する
    (
    1を選択
    関係階層から r
    ここで、r.parentid = p.id
    )

例のように E が person テーブルに存在するが、 relationshiphierarchy テーブルには存在しないように、子 ID が存在するかどうかを確認するだけでは十分ではありません。

于 2013-07-16T13:00:09.410 に答える