web-dev-qa-db-ja.com

親子ツリー階層順

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、
 [Active] [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 [PRIMARY] 
)ON [PRIMARY] 
 
 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 | FILTERDESC |アクティブ| 
 ------------------------------------------- ------- 
 | 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とルートのparentid = 0FilterDescsは単なるサンプルの説明なので、順序付けのためにそれらを解析することはできません。

質問

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

私の友達と私は試しましたが、実用的な解決策には達していませんが、引き続き試します。私はSQLをかなり初めて使用しているので、これは簡単に行うことができ、必要以上に困難にしています。

例(望ましい)出力:

 | ICFILTERID | PARENTID | FILTERDESC |アクティブ| 
 ------------------------------------------- ------- 
 | 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 | 
21
Archangel33

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];
25
Travis

上記は私には正しく動作しないようです。 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のように形成して輪郭を描くように投稿をインデントするには(レベルが深くなるほど、左から余白を増やす必要があります)、インデントという列もあります。ルートは0で、ユニオンにはc.Indent + 1 AS Indentがあります。コードでは、インデントを掛けて、32pxを想定し、コメントをニース階層とアウトラインで表示できます。

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

1
Guss Davey
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

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

0
Wohoooo