親子ツリー階層順序


21

SQL Server 2008 R2のデータをフォローする必要があります。SQLFiddle

スキーマ:

CREATE TABLE [dbo]。[ICFilters](
   [ICFilterID] [int] IDENTITY(1,1)NOT NULL、
   [ParentID] [int] NOT NULL DEFAULT 0、
   [FilterDesc] [varchar](50)NOT NULL、
   [アクティブ] [tinyint] NOT NULL DEFAULT 1、
 CONSTRAINT [PK_ICFilters] PRIMARY KEY CLUSTERED 
 ([ICFilterID] ASC)WITH 
    PAD_INDEX = OFF、
    STATISTICS_NORECOMPUTE = OFF、
    IGNORE_DUP_KEY = OFF、
    ALLOW_ROW_LOCKS = ON、
    ALLOW_PAGE_LOCKS = ON
 )ON [プライマリ]
)ON [プライマリ]

INSERT INTO [dbo]。[ICFilters](ParentID、FilterDesc、Active)
値 
(0、 '製品タイプ'、1)、
(1、 'ProdSubType_1'、1)、
(1、 'ProdSubType_2'、1)、
(1、 'ProdSubType_3'、1)、
(1、 'ProdSubType_4'、1)、
(2、 'PST_1.1'、1)、
(2、 'PST_1.2'、1)、
(2、 'PST_1.3'、1)、
(2、 'PST_1.4'、1)、
(2、 'PST_1.5'、1)、
(2、 'PST_1.6'、1)、
(2、 'PST_1.7'、0)、
(3、 'PST_2.1'、1)、
(3、 'PST_2.2'、0)、
(3、 'PST_2.3'、1)、
(3、 'PST_2.4'、1)、
(14、 'PST_2.2.1'、1)、
(14、 'PST_2.2.2'、1)、
(14、 'PST_2.2.3'、1)、
(3、 'PST_2.8'、1)

表:

| ICFILTERID | PARENTID | フィルターデスク| アクティブ|
--------------------------------------------------
| 1 | 0 | 製品タイプ| 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 3 | 1 | ProdSubType_2 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 20 | 3 | PST_2.8 | 1 |

すべての行には、その親のIDとルートのIDがありますparentid = 0FilterDesc私は順序のものを解析しようとすることはできませんのでsがちょうどサンプル記述されています。

質問

ツリーのようにすべての行を選択することは可能ですか?もしそうなら、どのように?「ツリーのような」と言うときは、親を再帰的に選択し、その後にそのすべての子を選択し、次にそれらの各子のすべての子を選択します。深さ優先のツリートラバーサル。

私の友人と私は試してみましたが、私たちは実用的なソリューションに欠けていますが、試してみます。私はsqlにかなり慣れていないので、これを簡単に行うことができ、必要以上に難しくしているだけです。

例(望ましい)出力:

| ICFILTERID | PARENTID | フィルターデスク| アクティブ|
--------------------------------------------------
| 1 | 0 | 製品タイプ| 1 |
| 2 | 1 | ProdSubType_1 | 1 |
| 6 | 2 | PST_1.1 | 1 |
| 7 | 2 | PST_1.2 | 1 |
| 8 | 2 | PST_1.3 | 1 |
| 9 | 2 | PST_1.4 | 1 |
| 10 | 2 | PST_1.5 | 1 |
| 11 | 2 | PST_1.6 | 1 |
| 12 | 2 | PST_1.7 | 0 |
| 3 | 1 | ProdSubType_2 | 1 |
| 13 | 3 | PST_2.1 | 1 |
| 14 | 3 | PST_2.2 | 0 |
| 17 | 14 | PST_2.2.1 | 1 |
| 18 | 14 | PST_2.2.2 | 1 |
| 19 | 14 | PST_2.2.3 | 1 |
| 15 | 3 | PST_2.3 | 1 |
| 16 | 3 | PST_2.4 | 1 |
| 20 | 3 | PST_2.8 | 1 |
| 4 | 1 | ProdSubType_3 | 1 |
| 5 | 1 | ProdSubType_4 | 1 |

CTEを使用するのがベストだろう
キンシャー

1
これは、特定の順序でテーブルデータをロードすることなく、目的の結果の並べ替えを示すスレッドです。row_number()とpartition byを使用して、目的の並べ替えを可能にする「パス」を作成します。ask.sqlservercentral.com/questions/48518/...

回答:


25

OK、十分な脳細胞が死んでいます。

SQLフィドル

WITH cte AS
(
  SELECT 
    [ICFilterID], 
    [ParentID],
    [FilterDesc],
    [Active],
    CAST(0 AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters]
  WHERE [ParentID] = 0
  UNION ALL
  SELECT 
    i.[ICFilterID], 
    i.[ParentID],
    i.[FilterDesc],
    i.[Active],  
    Level + CAST(i.[ICFilterID] AS varbinary(max)) AS Level
  FROM [dbo].[ICFilters] i
  INNER JOIN cte c
    ON c.[ICFilterID] = i.[ParentID]
)

SELECT 
  [ICFilterID], 
  [ParentID],
  [FilterDesc],
  [Active]
FROM cte
ORDER BY [Level];

2
これはまさに私が必要としたものです!これで死んだ脳細胞が多すぎることに同意します。私は自分が何を望んでいたのかはっきりしていませんでしたか?その場合、今後の参考のために質問を編集します。私は間違いなくそれを必要以上に難しくしてい
Archangel33

1
@ Archangel33あなたは問題とあなたが必要なものをレイアウトする良い仕事をしました。さらに、sqlfiddleは本当に役立ちます。
トラビス

2
+1だけそのアイテムが正しい順序で挿入されているが、選別のための他のフィールドはまだOTによって実装されていない動作するソートする[ICFilterID] [INT] IDENTITY(1,1)を用い
bummi

4
これが100%正しい解決策だとは思いません。難しいことですが、すべての行を階層内の正しいレベルでリストしますが、質問で求められた順序ではリストしません。質問に従って正しい順序で行をリストすることは可能でしょうか?それも私が探しているものです。

1
[FilterDesc]列の提供されたデータは架空のものであり、その順序は不要/重要ではないので、これは私の質問に答えます。@Travis Ganの答えのロジックに従って、この順序を取得するために必要なことは、にもう1つ追加CASTすることだけLevelです。例えば。Level + CAST( CAST(i.[ICFilterID] AS varbinary(max)) AS LevelになりLevel + CAST(i.[FilterDesc] AS varbinary(max)) + CAST(i.[ICFilterID] AS varbinary(max)) AS Levelます。
大天使

1

上記は私には正しく動作しないようです。facebookタイプのデータで2つのテーブルをセットアップすることを想像してください。表1には、PostIdとその他のフィールドがあります。PostIdは自動インクリメントであり、インターフェースでは明らかにDESCをソートして、最新の投稿を最上部に表示します。

次に、コメントテーブルについて説明します。表2この表CommentIdは、主キーである自動番号です。あなたのGUIでは、ASCを表示したいので、スレッドを読むときに意味があります。(一番上の最も古い(小さい番号))表2の他の重要なキーは、PostId(投稿に戻るFK)、およびParentId(コメントにFKする)です。これは、投稿の「ルート」コメントの場合、ParentIdはNULLになります 誰かがコメントに返信すると、parentIdにcommentidが入力されます。
皆さんがドリフトを取得することを願っています。CTEは次のようになります。

WITH  Comments
        AS ( SELECT  CommentId , ParentId, CAST(CommentId AS VARBINARY(MAX)) AS Sortkey, 0 AS Indent
             FROM    dbo.Comments
             WHERE   ParentId IS NULL AND PostId = 105
             UNION ALL
             SELECT  b.CommentId , b.ParentId,  c.Sortkey + CAST(b.CommentId AS varbinary(max))  AS Sortkey, c.Indent + 1 AS Indent
             FROM    dbo.Comments b
             INNER JOIN Comments c ON c.CommentId = b.ParentId
           )
   SELECT   *
   FROM     Comments
   ORDER BY Sortkey

サンプル出力

1   NULL    0x0000000000000001  0
5   1   0x00000000000000010000000000000001  1
6   5   0x000000000000000100000000000000010000000000000005  2
2   NULL    0x0000000000000002  0

F / Bポスト105に2つのコメント(CommentIds 1および2)があり、誰かがComment1(CommentId 5、ParentId 1)に返信し、次に他の誰かがその返信にコメントしたので、Comment5(CommentId 6、ParentId 6)

そして、ビオラ、順序は正しい、投稿の下で、正しい順序でコメントを表示できるようになりました。投稿をインデントしてFacebookのように形成し、輪郭を描くように(レベルが深くなるほど、左から余白を増やす必要があります)、Indentという列もあります。ルートは0で、ユニオンにはc.Indent + 1 AS Indentがあります。コードでは、yoでインデントに32pxを想定し、コメントを素敵な階層とアウトラインで表示できます。

+1をシードするデータベース管理キーを台無しにするよりも、日付(commentdate)を台無しにする方が良いため、SortKeyを構築するための原動力として自動増分主キーCommentIdを使用しても問題はありません。


0
create table pc ( parent varchar(10), child varchar(10) )

insert into pc values('a','b');
insert into pc values('a','c');
insert into pc values('b','e');
insert into pc values('b','f');
insert into pc values('a','d');
Insert into pc values('b','g');
insert into pc values('c','h');
insert into pc values('c','i');
insert into pc values('d','j');
insert into pc values('f','k');
insert into pc values('x','y');
insert into pc values('y','z');
insert into pc values('m','n');

 DECLARE @parent varchar(10) = 'a';
 WITH cte AS
 (
  select null parent, @parent child, 0 as level
   union
  SELECT  a.parent, a.child , 1 as level
    FROM pc a
   WHERE a.parent = @parent
   UNION ALL
  SELECT a.parent, a.child , c.level +    1
  FROM pc a JOIN cte c ON a.parent = c.child
  )
  SELECT distinct parent, child , level
  FROM cte
  order by level, parent

これにより、すべての子孫とレベルが表示されます。
お役に立てれば :)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.