2016-03-25 10 views
0

私は自己参照テーブルを持っています:レコードが階層構造(レコード階層と呼ばせてください)に順序付けられることを可能にするIDとPARENTID列があります。自己参照テーブルからルートレコードを取得する

このテーブルからレコードのリストを返すクエリ(「クエリA」とも呼ばれます)があります。返されるレコードの中には、「ルートレコード」(PARENTID = NULL)、ルートレコード以外のもの(PARENTID!= NULL)があります。 「クエリA」は、同じレコード階層に属する複数のレコードを返すことができることに注意してください。

最も効率的な方法で達成する必要があるのは、「クエリA」によって返されるすべてのレコードのルートレコードを取得して、「クエリA」のルート以外のレコードを検索することです彼らのルートレコードのために。あなたは、あなたが以下のアプローチを使用することができ、各項目のRoot項目を検索したい場合は

+1

このクエリは何ですか?ストアドプロシージャ?ビュー?ただプレーンSQL? –

+0

Zoher:単純なSQLクエリです。 – Daniel

+0

クエリを投稿できますか? –

答えて

1

可能な解決策の一つ:

declare @TableA table 
(
    ID int, 
    ParentID int NULL, 
    Name varchar(100) 
) 

insert into @TableA(ID, ParentID, Name) 
values 
(1, NULL, 'root 1'), 
(2, NULL, 'root 2'), 
(3, 2, 'node 3->2'), 
(4, 1, 'node 4->1'), 
(5, 4, 'node 5->4->1'), 
(6, 3, 'node 6->3->2'), 
(7, 4, 'node 7->4->1'), 
(8, 7, 'node 8->7->4->1') 


;with QueryA as 
(
    /* your query could be here */ 
    select t.ID, t.Name 
    from @TableA t 
    where t.ID in (1, 3, 8) 
), 
Tree as 
(
    select t.ID, t.ParentID, t.Name, 
    case when t.ParentID is NULL then t.ID end as RootID 
    from @TableA t 
    /* starting from rows we have in QueryA */ 
    where t.ID in (select q.ID from QueryA q) 

    union all 

    select tt.ID, t.ParentID, t.Name, 
    case when t.ParentID is NULL then t.ID end as RootID 
    from @TableA t 
    /* recursion to parents */ 
    inner join Tree tt on tt.ParentID = t.ID 
) 
select q.ID, q.Name, t.Name as RootName 
from QueryA q 
inner join Tree t on t.ID = q.ID and t.RootID is not NULL 
order by 1, 2 

また、あなたが釜から始めることができますQueryAにリンクせずにツリーを分割する(テーブル全体)。少しシンプルに見えます。この場合、最後のステートメントでのみQueryAを参照します。

0

:あなたは、whileループの後に見ることができるように

select t1.*,(case when t1.PARENTID is null then t1.ID else t1.PARENTID end) Id_Root , 0 IsTraced into #tmp 
from TableName t1 
left outer join TableName t2 on t1.ID=t1.PARENTID 
order by t1.PARENTID 

while exists(select TOP 1 * , (select PARENTID from #tmp where ID=t1.PARENTID) Id_GrandParent from #tmp t1 where IsTraced=0 order by PARENTID desc) 
begin 
     Declare @CurrentID as uniqueIdentifier 
     set @CurrentID = (select TOP 1 ID from #tmp t1 where IsTraced=0 order by PARENTID desc) 
     Declare @CurrentParentID as uniqueIdentifier 
     set @CurrentParentID = (select TOP 1 PARENTID from #tmp t1 where IsTraced=0 order by PARENTID desc) 
     Declare @CurrentGrandParentID as uniqueidentifier 
     set @CurrentGrandParentID=(select PARENTID from #tmp where [email protected]) 

     if(@CurrentGrandParentID is null) 
     begin 
      update #tmp set IsTraced=1 where [email protected] 
     end 
     else 
     begin 
      update #tmp set PARENTID= @CurrentGrandParentID, [email protected] where [email protected] 
     end 
end 

select ID,Id_Root 
from #tmp 
order by PARENTID 

あなたはID取得しTemp Table #tmp

から各要素の Id_Rootすることができます
+0

この回答が特定のルートレコードのみを取得する要件をどのように満たしているかわかりません。これらのクエリは、それらのすべてを選択します。 – Daniel

+0

@ダニエル私は自分の答えを編集し、テーブル内のすべてのアイテムとそれらのルート項目を取得する方法を追加しました – Karamafrooz

+0

ありがとう、私はそれを調べます。 – Daniel

0

これはトリック質問ですか?まず、各レコードには親が1つしかありません。また、ルートレコードには親の値がNULLになります。したがって、ルートレコードだけを取得するために複雑な作業を行う必要はありません。

Select * from QueryA where PARENTID is null 

は、クエリエンジンによって、すべてのレコードの本当に網羅searc時間後にあなたのすべてのルートレコードを取得します! PARENTIDがnullでない他のすべてのレコードは、ルートレコードではなく、定義上の子レコードです。

+1

質問をもう一度お読みください。 NULLのフィルタリングはSQL 101のものです。私はそれが事実であるかどうか質問しません。 – Daniel

+0

あなたの質問は明らかに分かりませんでした。自分で参照するデータセットを使用するプロジェクト管理システムを開発しましたので、あなたが何を求めているのか分かっていれば、私はあなたの質問に答えることができます。それは何ですか?PARENTIDがヌルであるレコードはいくつですか?それはちょうど1か> 1ですか? – nolaspeaker

関連する問題