php mysql альтернатива использованию того же запроса снова внутри цикла

Возможный дубликат:
Можно ли запросить таблицу древовидной структуры в MySQL одним запросом на любую глубину?

У меня есть административная область, которую я создал, которая извлекает данные из базы данных mysql с помощью php и отображает результаты в виде таблицы. В основном это показывает родительскую категорию, затем первую подкатегорию под ней, затем подкатегорию / предмет третьего уровня.

Он работает отлично, но, поскольку я новичок в mysql и php, я уверен, что он должен быть улучшен для экономии ресурсов базы данных, так как при построении таблицы я использую 3 цикла while и в каждом цикле выполняю запрос mysql, которым я являюсь конечно это неправильный способ сделать это.

Может кто-нибудь предложить мне некоторую помощь для лучшего способа сделать это?

Вот код:

           $query = mysql_query("SELECT * FROM categories WHERE
parent_id is null
order by cat_id asc;", $hd)
or die ("Unable to run query");       

while ($row = mysql_fetch_assoc($query)) {
echo '<tr style="font-weight:bold;color:green;"><td>'. $row    ['cat_id'].'</td><td>'.$row['cat_name'].'</td><td>'.$row    ['parent_id'].'</td><td>'.$row['active'].'</td><td>'.$row    ['url'].'</td><td>'.$row['date_updated'].'</td></tr>' ;

$query2 = mysql_query("SELECT * FROM categories WHERE
                (active = 'true' AND parent_id = ".$row    ['cat_id'].")
                order by cat_id asc;", $hd)
      or die ("Unable to run query");
while ($row2 = mysql_fetch_assoc($query2)) {
echo '<tr style="font-weight:bold;"><td>'. $row2['cat_id'].'</td><td>'.$row2    ['cat_name'].'</td><td>'.$row2['parent_id'].'</td><td>'.$row2    ['active'].'</td><td>'.$row2['url'].'</td><td>'.$row2    ['date_updated'].'</td></tr>' ;
    $query3 = mysql_query("SELECT * FROM categories WHERE
                (active = 'true' AND parent_id = ".$row2    ['cat_id'].")
                order by cat_id asc;", $hd)
      or die ("Unable to run query");
      while ($row3 = mysql_fetch_assoc($query3)) {
echo '<tr><td>'. $row3['cat_id'].'</td><td>'.$row3['cat_name'].'</td><td>'.$row3    ['parent_id'].'</td><td>'.$row3['active'].'</td><td>'.$row3    ['url'].'</td><td>'.$row3['date_updated'].'</td></tr>' ;

}
}
}

РЕДАКТИРОВАТЬ

Итак, я провел небольшое исследование, и вот где я нахожусь:

Вероятно, для небольшой базы данных мой подход в порядке.

Для большой базы данных, использующей массив для хранения данных, вероятно, будет означать, что мне нужно использовать рекурсивный подход, который может использовать слишком много памяти. Хотелось бы услышать, что думают люди, было бы все же лучше, чем зацикливание запросов к базе данных во вложенных циклах while?

Я нашел следующую ветку, где есть ответ, чтобы сделать это без рекурсии и только с одним запросом. Не уверен, если мне нужно добавить столбец позиции в мой текущий дизайн: Как построить неограниченный уровень меню с помощью PHP и MySQL

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

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

2 ответа

Я думаю, вы могли бы сделать что-то вроде этого:

SELECT * FROM categories
WHERE active = 'true'
ORDER BY parent_id, cat_id

Это даст вам все ваши категории, упорядоченные по parent_id, а затем по cat_id. Затем вы должны взять набор результатов и построить из него многомерный массив. Затем вы можете просмотреть этот массив так же, как в настоящее время, чтобы вывести категории.

Хотя это лучше с точки зрения доступа к БД, он также потребляет больше памяти, так как вам нужно хранить этот больший массив в памяти. Так что это действительно компромисс, который вы должны рассмотреть.

Здесь многое можно исправить, но я просто отвечу на ваш вопрос об уменьшении количества запросов. Я предлагаю всем вместе избавиться от предложений WHERE и использовать операторы if в цикле while. Используйте внешние переменные для хранения всех результатов, которые соответствуют определенному условию, а затем отобразите их все сразу после цикла. Примерно так (для краткости я положил кучу ваших вещей в переменные)

//before loop
$firstInfoSet = '';
$secondInfoSet = '';
$thirdInfoSet = '';

//in while loop

if($parentID == NULL)
{
  $firstInfoSet.= $yourFirstLineOfHtml;
}

if($active && $parentID == $catID) // good for query 2 and 3 as they are identical
{
  $secondInfoSet.= $yourSecondLineOfHtml;
  $thirdInfoSet.= $yourThirdLineOfHtml;
}

//after loop
echo $firstInfoSet . $secondInfoSet . $thirdInfoSet;

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

--EDIT-- После лучшего понимания вопроса...

$query = mysql_query("SELECT * FROM categories order by cat_id asc;", $hd);
$while ($row = mysql_fetch_assoc($query)){
   if($row['parent_id'] == NULL){
      //echo out your desired html from your first query 
   }
   if($row['active'] && $row['parent_id']== $row['cat_id']){
      //echo out your desired html from your 2nd and 3rd queries
   }
}
Другие вопросы по тегам