MySQL SELECT Tree Родительские идентификаторы - PullRequest
3 голосов
/ 16 апреля 2011

Как можно отсортировать записи оператора SELECT, чтобы они представляли действительное дерево?

Все мои попытки показывают вложенные узлы под неправильными родительскими узлами. Какой самый надежный способ добиться этого заказа?

Данные

ID      Parent ID      Title
--------------------------------------------
0       NULL           Root
1       0              Node A
2       0              Node B
3       1              Sub-Node C
4       1              Sub-Node D
5       3              Sub-Node E

выход

ID      Parent ID      Title
--------------------------------------------
0       NULL           Root
1       0              Node A
3       1              Sub-Node C
5       3              Sub-Node E
4       1              Sub-Node D
2       0              Node B

Визуализация данных

Root
    Node A
        Sub-Node C
            Sub-Node E
        Sub-Node D
    Node B

Ответы [ 5 ]

13 голосов
/ 16 апреля 2011

Вы можете использовать Вложенные Наборы. Проверьте эту статью:

Управление иерархическими данными в MySQL

Автор описывает несколько различных методов построения иерархий в SQL, а также примеры запросов. Это очень хорошая статья на эту тему!

5 голосов
/ 17 апреля 2011

Следуя совету @Blindy, я реализовал этот вид с помощью PHP. Вот две функции, которые, кажется, решают эту проблему относительно легко.

protected function _sort_helper(&$input, &$output, $parent_id) {
    foreach ($input as $key => $item)
        if ($item->parent_id == $parent_id) {
            $output[] = $item;
            unset($input[$key]);

            // Sort nested!!
            $this->_sort_helper(&$input, &$output, $item->id);
        }
}

protected function sort_items_into_tree($items) {
    $tree = array();
    $this->_sort_helper(&$items, &$tree, null);
    return $tree;
}

Мне было бы интересно услышать, если есть более простой подход, но это, кажется, работает.

4 голосов
/ 16 апреля 2011

MySQL не поддерживает рекурсивные запросы

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

См. Эти посты для некоторых идей и примеров:

Иерархия категорий (PHP / MySQL)

как мы можем написать запрос MySQL гдеУ родительского идентификатора есть дочерний идентификатор, и в следующий раз, когда дочерний идентификатор является родительским идентификатором, как я могу это сделать?

0 голосов
/ 09 марта 2013

Вот еще один способ сделать вашу функцию PHP.

function buildTree() {
  $data = array();
  $pointers = array();

  $sql = "SELECT ID,PARENT,TITLE FROM TREE ORDER BY TITLE ASC";
  $res = $this->db->query($sql);

  while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
    if(!isset($pointers[$row['ID']])) {
      $pointers[$row['ID']] = $row;
    }

    if(!empty($row['PARENT'])) {
      if(!isset($pointers[$row['PARENT']])) {
        $pointers[$row['PARENT']] = $row;
      }
      $pointers[$row['PARENT']][$row['ID']] =  &$pointers[$row['ID']];
    } else {
      $data[$row['ID']] = &$pointers[$row['ID']]; // This is our top level
    }
  }

  unset($pointers);
  return $data;
}
0 голосов
/ 20 февраля 2013

Я только что закончил эту рекурсивную функцию и подумал, что это элегантный способ решения проблемы.Вот что я сделал, когда сделал основной запрос SELECT MySQL:

function orderChildren($data){
    $tree = array();
    foreach($data as $value){
        if($value['parent_id'] == null){  // Values without parents
            $tree[$value['id']] = $this->goodParenting($value, $data);
        }
    }
    return $tree;
}

private function goodParenting($parent, $childPool){
    foreach($childPool as $child){
        if($parent['id'] == $child['parent_id']){
            $parent['children'][$child['id']] = $this->goodParenting($child, $childPool);
        }
    }
    return $parent;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...