Выборка из MySQL с рекурсией, решение на PHP

Author Автор: Роман Чернышов    Опубликовано: 9 октября 2014

treeКак известно рекурсивные запросы MySQL не поддерживает, что порождает множество сложностей при необходимости получить данные, например в древовидной структуре. Но есть ряд изящных решений на PHP, которые можно использовать, для построения древовидных массивов из полученных данных от БД.

Сразу оговорюсь. Распространенный метод, которым пользуются многие новички, не самый лучший и даже более того, он может положить весь веб-сервер на лопатки, или выбить из процессов MySQL. Как минимум это чревато сильными притормаживании при работе такого метода. Что это я, все вокруг да около, собственно вот он сам метод:

(в примере используется класс для работы с БД и его методы: getAll — выборка списка строк из БД)

$sql="SELECT * FROM table WHERE parent_id = 0 ORDER BY id ASC"; // получаем список элементов лежащих в корне
$items = $DB->getAll($sql); // получаем список записей из БД
 
$new_array = array(); // Новый массив, содержащий дерево
foreach($items as $item) {
  $sql="SELECT * FROM table WHERE parent_id = '{$item['id']}' ORDER BY id ASC"; // получаем список элементов потомков
  $items_2 = $DB->getAll($sql); // получаем список записей из БД
  $item['child'] = $items_2;
  $new_array[]=$item;
}

Многочисленные запросы в БД для выборки потомков и построения дерева. Вариант, но крайне нагружающий MySQl. Так, что я предостерегаю вас от его использования.

По этому, следует использовать немного модифицированный алгоритм, где выборка будет происходить единожды, и выбираться будет сразу вся таблица из БД, а уже далее средствами PHP производиться раскладка выборки в многомерный древовидный массив. Пример:

$sql="SELECT * FROM table ORDER BY id ASC"; // получаем список элементов лежащих в корне
$rs= $DB->getAll($sql); // получаем список записей из БД
 
$rs2 = array();
foreach ($rs as $row) {
    $rs2[$row['parent_id']][] = $row;
}
 
function RecursiveTree2(&$rs,$parent)
{
    $out = array();
    if (!isset($rs[$parent])) {
        return $out;
    }
    foreach ($rs[$parent] as $row) {
        $chidls = RecursiveTree2($rs, $row['id']);
        if ($chidls) $row['childs'] = $chidls;
        $out[] = $row;
    }
    return $out;
}
print_r(RecursiveTree2($rs2 ,0));

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

Следующий пример, вообще решает задачу в рамках одного цикла. При этом используется вспомогательный массив, которых хранит значение, а именно «путь» к родительскому элементу ветки, с целью дописать к нему новую ветку(потомка).
Пример: $x[1][‘childs’][1][‘childs’][0], таким образом мы знаем куда дописать потомка и тем самым построить дерево.

$sql="SELECT * FROM table ORDER BY id ASC"; // получаем список элементов лежащих в корне
$rs= $DB->getAll($sql); // получаем список записей из БД
 
$tree = array(0=>array('id'=>0, 'parent_id'=>0, 'value'=>'root'));
$temp = array(0=>&$tree[0]);
 
foreach ($rs as $val) {
    $parent = &$temp[ $val['parent_id'] ];
    if (!isset($parent['childs'])) {
        $parent['childs'] = array();
    }
    $parent['childs'][$val['id']] = $val;
    $temp[$val['id']] = &$parent['childs'][$val['id']];
}
unset($rs, $temp, $val, $parent);
print_r($tree[0]['childs']);

На закуску еще один пример вывода дерева, например такой пример может применяться при выводе категорий с вложенным неограниченным числом подкатегорий

SELECT ID, ParentID, Title FROM Tree;
 
<?php
while($row = mysql_fetch_assoc($res))
{  $tree[$row[ParentID]][$row[ID]] = $row[Title];}
 
function ShowTree($tree, $pid=0)
{
  echo ;
  foreach( $tree as $id => $root)
  {
    if($pid!=$id)continue;
    if(count($root))
    {
      foreach($root as $key => $title)
      {
        echo {$title};
        if(count($tree[$key]))ShowTree($tree,$key);
      }
    }
  }
  echo ;
}

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

Оставить комментарий

Автор блога
Роман Чернышов
Веб-разработчик,
Full Stack
Senior, Architect
PHP, JavaScript, Node.JS, Python, HTML 5, CSS 3, MySQL, Bash, Linux Admin
Заказать работу
предложить оффер

Моя книга
Книга. Веб-разработчик. Легкий вход в профессию
Печатная книга
Веб-разработчик.
Легкий вход в профессию
Купить за 159₽
Последние вопросы
Список вопросов
Последние комментарии
Меню

Archive

Мои проекты
Insurance CMS Love Crm CMS Совместные покупки Мой PHP Framework Хостинг для моих клиентов Лицензии на мой софт и поддержка