Упорядочение результатов MySQL для подчинения родителя / ребенка в оглавлении - PullRequest
0 голосов
/ 19 октября 2011

У меня есть таблица содержания, которая выглядит следующим образом:

  • ID
  • Parent_ID
  • Глава
  • Display_Order

Поэтому каждая строка является заголовком главы, но главы могут быть внутри глав, внутри глав. Поэтому приведенная выше таблица позволяет мне поддерживать эти отношения.

Если глава не имеет родителя, т. Е. Она не является подглавой любой другой главы, Parent_ID равен 'Null'. Если глава имеет родителя, то для Parent_ID устанавливается идентификатор родительской главы.

Поскольку в главе может быть несколько подглав, порядок этих подглав определяется через столбец Display_Order; 1 - первое и т. Д.

Может ли кто-нибудь предложить аккуратный SQL-запрос, который позволил бы мне выбрать всю таблицу и получить результат, который соответствует описанному выше? По сути, я ищу набор результатов, который отражает фактическую иерархию глав. ASCII TOC ниже!

Chapter
-- Chapter
---- Chapter
---- Chapter
---- Chapter
-- Chapter
---- Chapter
---- Chapter
Chapter
Chapter
* * Тысяча двадцать-одина и т.д.

1 Ответ

0 голосов
/ 19 октября 2011

Вы не можете сделать это только с 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 '&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();

Вот и все. Обратите внимание, что я пропустил инициализацию массива и не запускал этот пример кода, поэтому он может иметь синтаксическую ошибку, но принцип таков.

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

...