Postgres: подробные вложенные записи в рекурсивном запросе - PullRequest
0 голосов
/ 30 апреля 2018

Я работаю над простой системой комментариев, где пользователь может комментировать другие комментарии, создавая таким образом иерархию. Чтобы получить комментарии в иерархическом порядке, я использую Common Table Expression в Postgres.

Ниже приведены поля и используемый запрос:

id
user_id
parent_comment_id
message

WITH RECURSIVE CommentCTE AS (
    SELECT id, parent_comment_id, user_id
    FROM comment
    WHERE parent_comment_id is NULL

    UNION ALL

    SELECT child.id, child.parent_comment_id, child.user_id
    FROM comment child
    JOIN CommentCTE
    ON child.parent_comment_id = CommentCTE.id
)
SELECT * FROM CommentCTE

Приведенный выше запрос возвращает записи в широком порядке:

id       parent_comment_id       user_id
10              null                30
9               null                30
11               9                  30
14              10                  31
15              10                  31
12              11                  30
13              12                  31

Но можно ли изменить его, чтобы получить что-то вроде ниже, где записи возвращаются вместе для этого набора комментариев, в глубине, в первую очередь? Суть в том, чтобы получить данные таким образом, чтобы сделать рендеринг на внешнем интерфейсе более плавным.

id       parent_comment_id       user_id
9               null                30
11               9                  30
12              11                  30
13              12                  31
10              null                30
14              10                  31
15              10                  31

1 Ответ

0 голосов
/ 30 апреля 2018

Обычно я решаю эту проблему, синтезируя столбец «Путь», который можно отсортировать лексически, например, 0001:0003:0006:0009 является ребенком 0001:0003:0006. Каждая дочерняя запись может быть создана путем объединения элемента path с путем родителя. Вам не нужно возвращать этот столбец клиенту, просто используйте его для сортировки.

id       parent_comment_id       user_id     sort_key
9               null                30       0009
11               9                  30       0009:0011
12              11                  30       0009:0011:0012
13              12                  31       0009:0011:0012:0013
10              null                30       0010
14              10                  31       0010:0014
15              10                  31       0010:0015

Элемент path не должен быть чем-то конкретным, если он сортирует лексически в том порядке, в котором вы хотите сортировать дочерние элементы на этом уровне, и уникален на этом уровне. Основываясь на автоматическом увеличении идентификатора, это хорошо.

Использование элемента пути фиксированной длины, строго говоря, не обязательно, но облегчает рассуждение.

WITH RECURSIVE CommentCTE AS (
SELECT id, parent_comment_id, user_id, 
    lpad(id::text, 4) sort_key
FROM comment
WHERE parent_comment_id is NULL

UNION ALL

SELECT child.id, child.parent_comment_id, child.user_id, 
    concat(CommentCTE.sort_key, ':', lpad(id::text, 4))
FROM comment child
JOIN CommentCTE
ON child.parent_comment_id = CommentCTE.id
)
SELECT * FROM CommentCTE order by sort_key
...