Выберите родительский ряд и его детей и внуков - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть таблица комментариев, и я пытаюсь sh иметь возможность выбрать root комментарии (`ParentCommentId = 0), а затем из родительских комментариев, которые я получил, также выбрать все дети и дети этих детей и так далее

Например, я бы вернул строку для CommentId = 1038. Я также хотел бы, чтобы его ребенок (CommentId = 1039), потому что ParentCommentId = 1038, а затем также CommentId = 1040, потому что это ParentCommentId = 1039 и т. Д. c ..

enter image description here

Я попробовал следующий запрос, так как думаю, что я в правильном направлении.

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, изображенных ниже). Кажется, я получаю только комментарий root, и это первый ребенок, а не тот, у которого нет детей или root комментарии внучат.

enter image description here

1 Ответ

2 голосов
/ 15 апреля 2020

Вероятно, вам не хватает данных, потому что вы использовали inner join. Это проблематично c для случаев, когда прародителя нет в таблице, например:

  • для CommentID = 1036 нам не дают прародителя / родителя при извлечении данных
  • для любого комментария на уровне 1 иерархии (т.е. Parent = 0)

Использование left 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

Результаты

enter image description here

Бонус

Если вы хотите получить уровень в виде столбца, вы можете использовать рекурсивный 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);

Результаты: enter image description here

...