Рекурсивные категории с одним запросом?

У меня есть сайт со статьями и разделами, каждый раздел может иметь родительский раздел, сколько им нравится, например:

subject 1 -subject 2 --subject 3 -subject 4 --subject 5 --subject 6 ---subject 7 subject 8 subject 9 

и т.д..

Теперь, я хочу получить их рекурсивно, что является наиболее эффективным способом сделать это через php и mysql?

Tnx в продвинутом режиме.

Solutions Collecting From Web of "Рекурсивные категории с одним запросом?"

Если дерево не слишком велико, вы можете просто построить дерево в PHP, используя некоторые умные ссылки.

 $nodeList = array(); $tree = array(); $query = mysql_query("SELECT category_id, name, parent FROM categories ORDER BY parent"); while($row = mysql_fetch_assoc($query)){ $nodeList[$row['category_id']] = array_merge($row, array('children' => array())); } mysql_free_result($query); foreach ($nodeList as $nodeId => &$node) { if (!$node['parent'] || !array_key_exists($node['parent'], $nodeList)) { $tree[] = &$node; } else { $nodeList[$node['parent']]['children'][] = &$node; } } unset($node); unset($nodeList); с $nodeList = array(); $tree = array(); $query = mysql_query("SELECT category_id, name, parent FROM categories ORDER BY parent"); while($row = mysql_fetch_assoc($query)){ $nodeList[$row['category_id']] = array_merge($row, array('children' => array())); } mysql_free_result($query); foreach ($nodeList as $nodeId => &$node) { if (!$node['parent'] || !array_key_exists($node['parent'], $nodeList)) { $tree[] = &$node; } else { $nodeList[$node['parent']]['children'][] = &$node; } } unset($node); unset($nodeList); 

Это даст вам структуру дерева в $tree с дочерними элементами в соответствующем дочернем слое.

Мы сделали это с довольно большими деревьями (>> 1000 элементов), и это очень стабильно и намного быстрее, чем выполнение рекурсивных запросов в MySQL.

Это зависит от того, как вы сохранили свои данные. В MySQL.com есть хорошая статья под названием « Управление иерархическими данными в MySQL», в которой говорится об этом.

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

 $query = "SELECT `name`,`id` from `table`"; 

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

Вы могли бы взглянуть на эту тему: как получить иерархическое меню из mysql, которое было открыто вчера, и это примерно то же самое.

Шахта также использует рекурсию с одним запросом …

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

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

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

 class menuSystem{ var $menu; var $db; #this variable is my db class assigned from the construct, I havent written the construct in, I can if you need it function startNav(){ $this->db->runQuery("select * from table order by parent asc"); $menu = array(0 => array('children' => array())); while ($data = $this->db->fetchArray()) { $menu[$data['category_id']] = $data; $menu[(is_null($data['parent']) ? '0' : $data['parent'] )]['children'][] = $data['category_id']; } $this->menu = $menu; $nav = '<ul>'; foreach($menu[0]['children'] as $child_id) { $nav .= $this->makeNav($menu[$child_id]); } $nav .= '</ul>'; } function makeNav($menu){ $nav_one = '<li>'."\n\t".'<a href="#">'$menu['name'].'</a>'; if(isset($menu['children']) && !empty($menu['children'])) { $nav_one .= "<ul>\n"; foreach($menu['children'] as $child_id) { $nav_one .= $this->makeNav($this->menu[$child_id]); } $nav_one .= "</ul>\n"; } $nav_one .= "</li>\n"; return $nav_one; } 

}

EDIT: извините, я использую это в своем коде как класс и думаю, что мне удалось вытащить его из класса для вас, но забыл, что мне нужно это $ this-> menu

ОБНОВЛЕНИЕ: Я думаю, что ниже из класса сейчас, извините за такой длинный ответ

 $result = mysql_query("select * from table order by parent_id asc"); $menu = array(0 => array('children' => array())); while ($data = mysql_fetch_array($result)) { $menu[$data['category_id']] = $data; $menu[(is_null($data['parent_id']) ? '0' : $data['parent_id'] )]['children'][] = $data['category_id']; } $global_menu = $menu; $nav = '<ul>'; foreach($menu[0]['children'] as $child_id) { $nav .= makeNav($menu[$child_id]); } $nav .= '</ul>'; function makeNav($menu) { global $global_menu; $nav_one = '<li>'."\n\t".'<a href="#">' . $menu['name'].'</a>'; if(isset($menu['children']) && !empty($menu['children'])) { $nav_one .= "<ul>\n"; foreach($menu['children'] as $child_id) { $nav_one .= makeNav($global_menu[$child_id]); } $nav_one .= "</ul>\n"; } $nav_one .= "</li>\n"; return $nav_one; } 

Надеюсь, поможет

Люк

первая часть статьи относится только к 4 уровням, последняя часть – это не то, что я хочу сделать.

моя структура что-то вроде этого:

 +-------------+----------------------+--------+ | category_id | name | parent | +-------------+----------------------+--------+ | 1 | test | NULL | | 2 | subject1 | 1 | | 3 | subject2 | 1 | | 4 | subject3 | 2 | | 5 | subject4 | 4 | +-------------+----------------------+--------+ 

Я не хочу усложнять вещи, я хочу сделать это самым простым способом, но для получения данных наиболее эффективным способом.

если предположить, что ваша таблица имеет id , id_parrent и поля имени

 function tree($id) { $query = "SELECT `name`,`id` from `table` WHERE `id_parrent` = '$id'"; $result = mysql_query($query); if(mysql_num_rows($result) != 0) { echo "<ul>"; while($row = mysql_fetch_array($result)) { echo "<li>",$row[name],"</li>"; tree($row[id]); } echo "</ul>"; } } 

так что вы получите все дерево

 category1 category1_1 category1_2 category1_2_1 category1_2_2 category1_3 ........................... 

Из вашего примера в каждую категорию сохраните полный путь в другом поле:
1 – 1
2 – 1,2
3 – 1.2.3
4 – 1,4
5 – 1,4,5
6 – 1.4.6
7 – 1.4.6.7
8 – 8
9 – 9

а затем просто запросите с ORDER BY в этом поле

У меня есть хорошее решение этой проблемы.

Он не использует рекурсию . И для этого требуется один запрос к базе данных.

Я только что опубликовал код в своем ответе на аналогичный вопрос:

https://stackoverflow.com/questions/2871861#3368622

Благодарю.