У меня есть следующая упрощенная структура таблицы базы данных для унаследованной системы, похожей на тикеты.
messages
id INT
parent_id INT
content TEXT
answer TEXT
...
В списке я показываю все сообщения. При нажатии на сообщение отображается его ответ и т. Д.
Проблема в том, что теперь мне нужна структура списка всех родители а также Дети связанные с этим сообщением, а также положение этого сообщения в дереве. Как я могу получить их из базы данных?
Я использую Laravel, но сырой SQL также поможет мне найти направление.
Пример:
╔════╦═══════════╦════════════════════════╦═══════ ══════════╗ ║ id ║ parent_id ║ содержание ║ ответ ║ ╠════╬═══════════╬════════════════════════╬═══════ ══════════╣ ║ 1 ║ NULL ║ Привет, у меня проблема ║ Я не могу помочь ║ ║ 2 ║ 1 ║ Проблема сохраняется ║ Хорошо, что это? ║ ║ 3 ║ 2 ║ Неважно, я понял ║ О, хорошо. ║ ║ 4 ║ 3 ║ Проблема вернулась ║ Какая проблема? ║ ║ 5 ║ 4 ║ Та же проблема снова ║ ... ║ ╚════╩═══════════╩════════════════════════╩═══════ ══════════╝
При отображении сообщения с id = 4
, Я должен быть в состоянии отобразить что-то вроде этого списка:
История сообщений:
— Привет у меня проблема
— Проблема сохраняется
— Неважно, я получил это
— Проблема вернулась
— Та же проблема снова
Я мог думать только о цикле и нескольких выполнениях SQL-запросов для каждого родителя и потомка, который выглядит как запах кода.
Как заявил Даан, этот вопрос кажется дубликатом для Как создать MySQL иерархический рекурсивный запрос.
Однако я решил не удалять его, поскольку Раван только что ответил на него с помощью подхода Laravel, который помог мне решить проблему, поэтому я просто оставлю это здесь для дальнейшего использования.
Поскольку вы выполняете иерархические операции, вы должны использовать стратегию для сохранения и извлечения этих данных из вашей базы данных.
Один подход заключается в использовании Модель вложенного набора, это может сделать это легче.
У Laravel есть отличный пакет, который имеет дело с этим, называется etrepat / Баум, это также объясняет, как это работает, и я цитирую:
Простой способ визуализировать, как работает вложенный набор, — думать о родительском объекте, окружающем все
его потомков и его родителей, окружающих его и т. д. Итак, это дерево:
root
|_ Child 1
|_ Child 1.1
|_ Child 1.2
|_ Child 2
|_ Child 2.1
|_ Child 2.2
Можно визуализировать так:
___________________________________________________________________
| Root |
| ____________________________ ____________________________ |
| | Child 1 | | Child 2 | |
| | __________ _________ | | __________ _________ | |
| | | C 1.1 | | C 1.2 | | | | C 2.1 | | C 2.2 | | |
1 2 3_________4 5________6 7 8 9_________10 11_______12 13 14
| |___________________________| |___________________________| |
|___________________________________________________________________|
Числа представляют левую и правую границы. Стол тогда мог
выглядеть так:
id | parent_id | lft | rgt | depth | data
1 | | 1 | 14 | 0 | root
2 | 1 | 2 | 7 | 1 | Child 1
3 | 2 | 3 | 4 | 2 | Child 1.1
4 | 2 | 5 | 6 | 2 | Child 1.2
5 | 1 | 8 | 13 | 1 | Child 2
6 | 5 | 9 | 10 | 2 | Child 2.1
7 | 5 | 11 | 12 | 2 | Child 2.2
Чтобы все дети родитель узел, ты
SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
Чтобы получить количество детей, это
(right - left - 1)/2
Чтобы получить узел и всех его предков, возвращаясь к корню, вы
SELECT * WHERE node.lft IS BETWEEN lft AND rgt
Как видите, запросы, которые будут рекурсивными и непомерно медленными
обычные деревья внезапно довольно быстро. Отличный, не так ли?
Других решений пока нет …