0

我有一个评论表,我试图完成能够选择根评论(`ParentCommentId = 0)然后从我回来的父评论中选择我所有的孩子和那些孩子的孩子等等

例如,我会取回CommentId = 1038. 我也想要它的孩子 ( CommentId = 1039) 因为ParentCommentId = 1038, 然后还CommentId = 1040因为它是ParentCommentId = 1039等等。

在此处输入图像描述

我尝试了以下查询,因为我认为我的方向是正确的。

SELECT *
FROM 
    (SELECT 
         c.CommentId,
         c.PostId,
         c.Comment,
         c.ParentCommentId,
         c.CommentDateTime
     FROM 
         [gallery].[Comments] c
     INNER JOIN 
         [player].[Players] p ON p.UserId = c.UserId 
     WHERE 
         c.PostId = 32
         AND ParentCommentId = 0) AS ParentComments
JOIN
    (SELECT 
         c.CommentId,
         c.PostId,
         c.Comment,
         c.ParentCommentId,
         c.CommentDateTime
     FROM 
         [gallery].[Comments] c
     INNER JOIN 
         [player].[Players] p ON p.UserId = c.UserId 
     WHERE 
         c.PostId = 32
         AND ParentCommentId != 0) AS ChildComments ON ParentComments.CommentId = ChildComments.ParentCommentId

但我肯定会得到错误的数据,比如与父母在同一行的孩子,理想情况下我希望孩子们成为单独的行。它也只有 1 个孩子的深度,而且肯定缺少很多评论(比下图的 5 个要多得多)。我似乎只得到一个根评论,它是第一个孩子,而不是任何没有孩子的孩子或根评论大孩子。

在此处输入图像描述

4

1 回答 1

2

您可能会丢失数据,因为您使用了inner join. 这对于祖父母不在表格中的情况是有问题的,例如:

  • 因为CommentID = 1036我们没有在数据提取中给出祖父母/父母
  • 对于层次结构级别 1 的任何评论(即 Parent = 0)

使用 aleft join应该可以解决这个问题。

使用的数据

declare @target table (
    CommentID int
    ,PostID int
    ,Comment varchar(200)
    ,ParentCommentId int
);

insert into @target
values
    (1036, 32, 'Que?', 1033)
    ,(1037, 32, 'What up mane', 1035)
    ,(1038, 32, 'Hi', 0)
    ,(1039, 32, 'Can you see me?', 1038)
    ,(1040, 32, 'Test', 1039)
    ,(1041, 32, 'T', 1038)
    ,(1042, 32, 'Yoooo', 0)
    ,(1043, 32, 'Test?', 1042)
    ,(1044, 32, 'Test 1', 1039)
    ,(1045, 32, 'Test 2', 1039)
;

获取层次结构

可以构建一个简单的层次结构表,显示三个层次

select 
    GrandParentCommentID = isnull(b.ParentCommentID, 0)
    ,a.ParentCommentID
    ,a.CommentID 
from @target as a 
left join @target as b on a.ParentCommentId = b.CommentID

完整答案

with Hierarchy as (
    select 
        GrandParentCommentID = b.CommentID
        ,a.ParentCommentID
        ,a.CommentID 
    from @target as a 
    inner join @target as b on a.ParentCommentId = b.CommentID
)
select 
    hier.GrandParentCommentID
    ,hier.ParentCommentID
    ,hier.CommentID
    ,details.Comment
from Hierarchy as hier
inner join @target as details on details.CommentID = hier.CommentID
order by
    hier.GrandParentCommentID
    ,hier.ParentCommentID

结果

在此处输入图像描述

奖金

如果您想将级别作为一列,您可以使用递归 CTE,如下所示(我相信有更好的方法):

;with Hierarchy as (
    select
        GrandParentCommentID = 0
        ,ParentCommentID = 0
        ,CommentID
        ,hier_level = 1
    from @target where ParentCommentID = 0

    union all
    select 
        GrandParentCommentID = h.ParentCommentID
        ,t.ParentCommentID
        ,t.CommentID
        ,hierarchy_level = h.hier_level + 1
    from Hierarchy as h
    inner join @target as t on t.ParentCommentId = h.CommentID
)
select * from Hierarchy

添加一个孙子进行演示:

insert into @target values (1045, 32, 'Test 2', 1039);

结果: 在此处输入图像描述

于 2020-04-15T04:22:45.653 回答