父子树层次结构订单


21

我必须遵循SQL Server 2008 R2中的数据。SQLFiddle

架构:

创建表[dbo]。[ICFilters](
   [ICFilterID] [int] IDENTITY(1,1)NOT NULL,
   [ParentID] [int] NOT NULL默认值0,
   [FilterDesc] [varchar](50)NOT NULL,
   [Active] [tinyint] NOT NULL默认值1,
 约束[PK_ICFilters]主键 
 ([ICFilterID] ASC)与 
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    IGNORE_DUP_KEY = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS =开启
 )在[PRIMARY]上
)在[PRIMARY]上

插入[dbo]。[ICFilters](ParentID,FilterDesc,活动)
价值观 
(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 | 父母 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和根的ID parentid = 0。该FilterDescs为刚刚样本的描述,所以我不能尝试解析那些排序。

问题

是否可以以树状方式选择所有行?如果是这样,怎么办?当我说“树状”时,我的意思是递归地选择父级,然后选择其所有子级,然后依次选择每个父级的所有子级,依此类推。深度优先的树遍历。

我和我的朋友们已经尝试过了,但我们仍未找到可行的解决方案,但会继续尝试。我对sql还是很陌生,所以也许可以很容易地做到这一点,而我只是使事情变得比必要的难。

示例(所需)输出:

| ICFILTERID | 父母 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 |

最好使用CTE
Kin Shah

1
这是一个显示所需结果排序的线程,而不必按任何特定顺序加载表数据。它使用row_number()和partition by来创建“路径”,以启用所需的排序。ask.sqlservercentral.com/questions/48518/…– 2014

Answers:


25

好,足够的脑细胞已经死了。

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,但使用[ICFilterID] [int] IDENTITY(1,1)进行排序仅适用于按正确顺序插入项目的情况,但是OT尚未实现用于排序的其他字段
-bummi

4
我不认为这是100%正确的解决方案。很难在层次结构中列出所有具有正确级别的行,而不会按问题要求的顺序列出它们。是否可以按照问题以正确的顺序列出行?这也是我在寻找的东西。

1
这确实回答了我的问题,因为[FilterDesc]列中提供的数据是虚拟的,并且该顺序是不必要/不重要的。继@Travis甘的回答逻辑都是一个必须做的就是这个顺序是另一种添加CASTLevel。例如。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
Archangel33

1

以上对我来说似乎无法正常工作。想象一下2表设置与Facebook数据类型。表1中有PostId +您其他字段。PostId是自动递增的,显然在您的界面中,您将对DESC进行排序,以使最新文章位于顶部。

现在为评论表。表2该表CommentId是主键,自动编号。在您的gui中,您想要显示它ASC,以便在读取线程时有意义。(顶部的最旧(较小的数字))表2中的其他重要键是:PostId(返回到帖子的FK)和ParentId(从FK到CommentId),如果这是对帖子的“根”注释,则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上,有两个评论(CommentId 1和2),然后有人对Comment1(CommentId 5,ParentId 1)进行了回复,然后其他人对该答复进行了评论,因此对Comment5(CommentId 6,ParentId 6)进行了评论。

中提琴,顺序正确,在帖子下,您现在可以按正确的顺序显示评论。为了使帖子缩进以使其像Facebook中一样形成和轮廓(级别越深,必须从左边距越多),我还有一列称为Indent。根为0,然后在联合中,我们得到c.Indent + 1 AS Indent在代码中,您现在可以将indent乘以let假定32px,并以漂亮的层次结构和轮廓显示注释。

我认为使用自动增量主键CommentId作为构建我的SortKey的驱动力没有问题,因为您搞乱日期(commentdate)要比搞乱以+1种子的数据库托管键更好。


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

这将为您提供所有后代和等级。
希望这可以帮助 :)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.