Как я могу сгенерировать древовидную структуру из таблицы в базе данных? - PullRequest
1 голос
/ 10 марта 2009

Я пытаюсь сгенерировать древовидную структуру из таблицы в базе данных. Таблица хранится без изменений, каждая запись имеет parent_id или 0. Конечная цель - создать поле выбора и массив узлов.

Код, который у меня есть на данный момент:

function init($table, $parent_id = 0) 
{

    $sql = "SELECT id, {$this->parent_id_field}, {$this->name_field} FROM $table WHERE {$this->parent_id_field}=$parent_id ORDER BY display_order";

    $result = mysql_query($sql);

    $this->get_tree($result, 0);

    print_r($this->nodes);
    print_r($this->select);
    exit;
}

function get_tree($query, $depth = 0, $parent_obj = null)
{   
    while($row = mysql_fetch_object($query))
    {   
        /* Get node */
        $this->nodes[$row->parent_category_id][$row->id] = $row;

        /* Get select item */
        $text = "";
        if($row->parent_category_id != 0) {
            $text .= "    ";
        }
        $text .= "$row->name";
        $this->select[$row->id] = $text;

        echo "$depth $text\n";

        $sql = "SELECT id, parent_category_id, name FROM product_categories WHERE parent_category_id=".$row->id." ORDER BY display_order";

        $nextQuery = mysql_query($sql);
        $rows = mysql_num_rows($nextQuery);

        if($rows > 0) {
            $this->get_tree($nextQuery, ++$depth, $row);
        }            
    }
}

Это почти работает, но не совсем. Кто-нибудь может мне помочь прикончить это?

Ответы [ 3 ]

4 голосов
/ 10 марта 2009

Вы почти наверняка не должны продолжать свой текущий путь. Рекурсивный метод, который вы пытаетесь использовать, почти наверняка снизит вашу производительность, если ваше дерево когда-нибудь станет еще немного больше. Вероятно, вам следует искать структуру вложенных множеств вместо списка смежности, если вы планируете часто читать дерево.

С помощью вложенного набора вы можете легко получить все дерево, вложенное правильно, с помощью одного запроса.

Пожалуйста, посмотрите эти вопросы для обсуждения деревьев.

Можно ли запросить таблицу древовидной структуры в MySQL одним запросом на любую глубину?

Реализация иерархической структуры данных в базе данных

Какой самый эффективный / элегантный способ разбить плоский стол на дерево?

1 голос
/ 10 марта 2009
    $this->nodes[$row->parent_category_id][$row->id] = $row;

Эта строка уничтожает ваш ORDER BY display_order. Измените его на

    $this->nodes[$row->parent_category_id][] = $row;

Моя следующая проблема - часть $ row-> parent_category_id. Разве это не должно быть просто $ row-> parent_id?

РЕДАКТИРОВАТЬ: О, я недостаточно внимательно прочитал ваш источник. Избавьтесь от предложения WHERE. Прочитайте всю таблицу сразу. Вам нужно опубликовать обработку дерева во второй раз. Сначала вы читаете базу данных в список массивов. Затем вы рекурсивно обрабатываете массив для вывода.

Ваш массив должен выглядеть так:

 Array(0 => Array(1 => $obj, 5 => $obj), 
       1 => Array(2 => $obj),
       2 => Array(3 => $obj, 4 => $obj),
       5 => Array(6 => $obj) );

 function display_tree() {
      // all the stuff above
      output_tree($this->nodes[0], 0); // pass all the parent_id = 0 arrays.
 }

 function output_tree($nodes, $depth = 0) {
     foreach($nodes as $k => $v) {
         echo str_repeat(' ', $depth*2) . $v->print_me();
         // print my sub trees
         output_tree($this->nodes[$k], $depth + 1);
     }
 }

 output:
 object 1
   object 2
     object 3
     object 4
 object 5
   object 6
0 голосов
/ 10 марта 2009

Я думаю, что вот эта строка:

if($row->parent_category_id != 0) {
    $text .= "    ";
}

должно быть:

while ($depth-- > 0) {
    $text .= "    ";
}

Вы делаете отступ только один раз, а не количество отступов.

И эта строка:

$this->get_tree($nextQuery, ++$depth, $row);

должно быть:

$this->get_tree($nextQuery, $depth + 1, $row);

Обратите внимание, что вам, вероятно, следует следовать совету, приведенному в другом ответе, и захватить всю таблицу сразу, а затем обработать ее сразу, потому что в целом вы хотите минимизировать количество обращений к базе данных (есть несколько используйте случаи, когда ваш способ работы более оптимален, например, если у вас очень большое дерево, и вы выбираете небольшую его часть, но я сомневаюсь, что это так)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...