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

Author Роман Чернышов    Category Без рубрики     Tags , , , Комментариев 0 Дата 9 Окт

tree Выборка из MySQL с рекурсией, решение на PHPКак известно рекурсивные запросы 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 ;
}

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

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

Консультации

Последние вопросы
Меню

Archive

Портфолио Все работы

с 2009 года по сегодняшний день, создано более 300 сайтов...