#php #mysql #hierarchical-data #tableofcontents
#php #mysql #иерархический-данные #tableofcontents
Вопрос:
У меня есть таблица для оглавления, которая выглядит следующим образом:
- ID
- Parent_ID
- Глава
- Display_Order
Следовательно, каждая строка является заголовком главы, но внутри глав могут быть главы внутри глав, внутри глав. Поэтому приведенная выше таблица позволяет мне поддерживать эти отношения.
Если у главы нет родительского элемента, т. Е. Она не является подразделом какой-либо другой главы, Parent_ID равен ‘Null’. Если у главы есть родительский элемент, его Parent_ID устанавливается на идентификатор родительской главы.
Поскольку в главе может быть несколько подразделов, порядок этих подразделов управляется с помощью столбца Display_Order; 1 является первым и т. Д.
Может ли кто-нибудь предложить аккуратный SQL-запрос, который позволил бы мне выбрать всю таблицу и получить результат, который выполняет вышеуказанное? По сути, я ищу набор результатов, который отражает фактическую иерархию глав. Оглавление ASCII ниже!
Chapter
-- Chapter
---- Chapter
---- Chapter
---- Chapter
-- Chapter
---- Chapter
---- Chapter
Chapter
Chapter
и т.д.
Комментарии:
1. Известно ли количество уровней?
2. Один запрос сможет вернуть все результаты только в Display_Order . Тогда вам просто нужно будет просмотреть результаты и идентифицировать их в зависимости от их родителя? Если вы не можете заставить это работать, возможно, посмотрите на модель списка смежности: sitepoint.com/hierarchical-data-database .
3. Еще лучше был бы метод «модифицированного обхода дерева предварительного заказа», упомянутый на следующей странице этой статьи. Этот метод позволяет ему получить полную иерархию в одном простом запросе. sitepoint.com/hierarchical-data-database-2
4. @Lumbendil количество уровней неизвестно, и оно также не может быть исправлено, поскольку оглавление должно быть очень гибким.
Ответ №1:
Вы не можете сделать это только с SQL-запросами (по крайней мере, в MySQL). Один из подходов с SQL и PHP заключается в следующем:
SELECT id, IFNULL(parent_id, 0) AS parentid, chapter FROM toc ORDER BY parentid, display_order
Затем вы считываете этот набор строк в массив $ a следующим образом:
while ($row = mysql_fetch_array($result)) {
$a[$row['id']]['name'] = $row['chapter'];
$a[$row['parentid']]['children'][] = $row['id'];
}
Это создаст фиктивный элемент с первым индексом 0.
Небольшой пример функции для печати отступа для заданного уровня (вы можете использовать CSS с заполнением вместо или любым другим способом для создания отступа):
function printIndent($level = 0) {
for ($j = 0; $j <= $level; $j ) echo 'amp;nbsp';
}
Затем вы создаете рекурсивную функцию printTree, которая выводит дерево:
function printTree($key = 0, $level = 0) {
if ($key > 0) {
printIndent($level);
echo $a[$key]['name'];
}
if (count($a[$key]['children'])
foreach ($a[$key]['children'] as $child)
printTree($child, $level 1);
}
и вы вызываете его один раз с:
printTree();
Это оно. Пожалуйста, обратите внимание, что я пропустил инициализацию массива и не запускал этот пример кода, поэтому в нем может быть синтаксическая ошибка, но принцип таков.
Недостатком этого подхода является то, что если у вас очень большое количество элементов, это будет не самым эффективным, поскольку сначала вы читаете все сразу в большой массив. Но для меньшего количества элементов это хорошее решение.
Комментарии:
1. Забыл добавить, что очень важно иметь именно этот ПОРЯДОК SQL-запроса, поскольку способ генерации массива зависит от этого: родители должны быть повторены перед их дочерними элементами. И, конечно же, он учитывает порядок отображения дочерних элементов одного и того же родителя.
2. Большое спасибо. Я согласен, это не масштабируемо, но это большой шаг вперед — это действительно доказывает точку зрения на данном этапе, и если мы начнем играть с большим количеством данных, я, вероятно, захочу перейти к базе данных, которая поддерживает рекурсию.