Рекурсивные категории с одним запросом?
У меня есть сайт со статьями и разделами,
каждая секция может иметь родительский раздел, насколько им нравится
например:
subject 1
-subject 2
--subject 3
-subject 4
--subject 5
--subject 6
---subject 7
subject 8
subject 9
и т.д..
Теперь, я хочу получить их рекурсивно, что является наиболее эффективным способом сделать это через php и mysql?
Tnx в расширенном режиме.
Ответы
Ответ 1
Если дерево не слишком велико, вы можете просто построить дерево в 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);
Это даст вам структуру дерева в $tree
с дочерними элементами в соответствующем children
-слоте.
Мы сделали это с довольно большими деревьями ( → 1000 элементов), и он очень стабилен и намного быстрее, чем выполнение рекурсивных запросов в MySQL.
Ответ 2
Это зависит от того, как вы храните свои данные. В MySQL.com есть хорошая статья под названием "Управление иерархическими данными в MySQL" , в которой говорится об этом.
Ответ 3
Ну, вы можете получить все категории в массиве только в одном запросе, как вы знаете:
$query = "SELECT `name`,`id` from `table`";
После этого в массиве вы можете построить дерево с некоторыми вложенными циклами. Он не будет быстрым, но простым и быстрым, чем использование рекурсивных запросов. Кроме того, вы можете кэшировать построенное дерево и не переделывать его каждый раз.
Ответ 4
Вы могли бы взглянуть на эту тему: как получить иерархическое меню из mysql, которое было открыто вчера, и это примерно то же самое.
Ответ 5
Mine также использует рекурсию с одним запросом...
Рекурсивный метод хранения иерархических данных без нескольких вызовов в базу данных
Я хотел использовать рекурсию также из-за ее простоты, но, как и вы, я хотел удалить накладные расходы рекурсивного запроса. В моей логике говорится, что вы просто перемещаете нагрузку из базы данных в память в зависимости от размера результата вашей базы данных, но я не проводил никаких реальных тестов масштабируемости, поэтому я не знаю, какое влияние на нее оказывает vs нерекурсивные методы.
Ответ 6
Я не могу гарантировать, что я не допустил никаких синтаксических ошибок, но это должно работать с одним запросом.
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;
}
Надеюсь, что это поможет
Лука
Ответ 7
первая часть статьи относится только к 4 уровням, последняя часть не так, как я хочу это сделать.
моя структура что-то вроде этого:
+-------------+----------------------+--------+
| category_id | name | parent |
+-------------+----------------------+--------+
| 1 | test | NULL |
| 2 | subject1 | 1 |
| 3 | subject2 | 1 |
| 4 | subject3 | 2 |
| 5 | subject4 | 4 |
+-------------+----------------------+--------+
Я не хочу усложнять вещи, я хочу сделать это самым простым способом, но для получения данных наиболее эффективным способом.
Ответ 8
если предположить, что ваша таблица имеет 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
...........................
Ответ 9
Из вашего примера в каждую категорию сохраните свой полный путь в другом поле:
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 в этом поле
Ответ 10
У меня есть хорошее решение этой проблемы.
Он не использует рекурсию. И для этого требуется один запрос.
Я только что опубликовал код в своем ответе на аналогичный вопрос:
fooobar.com/info/339905/...
Спасибо.