Обновить

Спасибо @forpas и @trincot за то, что они поделились своими решениями и идеями ниже. Я начал работать со следующим кодом (demo):

with recursive cte_comments as (
  select 
    *
  from
    comments
  where parent_comment_id = 1
  union all
  select
    this_execution.* 
  from
    cte_comments prev_execution
    inner join comments this_execution
      on this_execution.parent_comment_id = prev_execution.comment_id
) 

select * from cte_comments

Исходное сообщение

У меня есть следующая comments таблица и данные в базе данных SQLite:

Структура таблицы

-----------------------------------------
| Column            | Type              |
+++++++++++++++++++++++++++++++++++++++++
| comment_id        | integer           |
+---------------------------------------+
| parent_comment_id | integer           |
+---------------------------------------+
| comment_text      | text              |
-----------------------------------------

Данные таблицы

--------------------------------------------------------------------
| comment_id        | parent_comment_id  | comment_text            |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| 1                 |                    | First comment, level 1  |
--------------------------------------------------------------------
| 2                 | 1                  | First comment, level 2  |
--------------------------------------------------------------------
| 3                 | 2                  | First comment, level 3  |
--------------------------------------------------------------------
| 4                 | 2                  | First comment, level 3  |
--------------------------------------------------------------------
| 5                 |                    | Second comment, level 1 |
--------------------------------------------------------------------
| 6                 | 5                  | Second comment, level 2 |
--------------------------------------------------------------------
| 7                 | 6                  | Second comment, level 3 |
--------------------------------------------------------------------

Данные предназначены для вложенного раздела комментариев на веб-сайте, где comment_id уникален, а parent_comment_id может быть null. Два или более комментариев могут находиться под одним и тем же parent_comment_id. Столбец comment_text содержит случайные строки.

Вопрос

Как выполнить поиск SQL, который вернет все дочерние элементы под родительским комментарием? Например, когда я ищу все комментарии в комментарии 1, я хочу, чтобы комментарии 2, 3 и 4 (все комментарии, начинающиеся с Первый комментарий ) возвращались обратно. И когда я ищу все комментарии в комментарии 5, я хочу, чтобы комментарии 6 и 7 (все комментарии, начинающиеся с Второй комментарий ) вернулись обратно.

Нужно ли иметь промежуточный стол / стол для присоединения? Нужно ли менять структуру таблицы? Или мне нужно использовать другой движок базы данных, чтобы это произошло?

0
Zulhilmi Zainudin 20 Дек 2019 в 17:21

2 ответа

Лучший ответ

С рекурсивным CTE:

with recursive cte as (
  select * from comments
  where parent_comment_id = 1
  union all
  select t.* 
  from cte c inner join comments t
  on t.parent_comment_id = c.comment_id
) 
select * from cte

См. демонстрационную версию.
Полученные результаты:

| comment_id | parent_comment_id | comment_text           |
| ---------- | ----------------- | ---------------------- |
| 2          | 1                 | First comment, level 2 |
| 3          | 2                 | First comment, level 3 |
| 4          | 2                 | First comment, level 3 |
1
forpas 20 Дек 2019 в 14:33

Если ваша версия sqlite 3.8.4 или выше, вы можете использовать рекурсивное предложение with:

with recursive cte (id, name, parent_id) as (
  select     comment_id,
             comment_text,
             parent_comment_id 
  from       comments
  where      parent_comment_id = 1
  union all
  select     c.comment_id,
             c.comment_text,
             c.parent_comment_id
  from       comments c
  inner join cte
          on c.parent_comment_id = cte.comment_id
)
select * from cte;

В условии parent_comment_id = 1 вы должны указать идентификатор комментария, из которого должны быть получены потомки.

1
trincot 21 Дек 2019 в 07:26