Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Два запроса к базе или один?
 
 автор: Лена   (04.07.2008 в 14:05)   письмо автору
 
 

У меня вертикальное меню, которое занимается выводом контента.
Вот код:

<?php
include("configs/dbopen.php");
require (
"smarty/Smarty.class.php");
$smarty = new Smarty;
function 
ShowTree($parent_id){
global 
$link$smarty$list;

     
$sql "SELECT * FROM `menu` WHERE `pid` = "$parent_id ." ORDER BY `id_menu`";
//echo "(st): $sql<br>";
    
$result mysql_query($sql$link);

     if (
$parent_id!=0$list .= "<ul> <!-- parent = $parent_id -->\n";
     while (
$row mysql_fetch_assoc($result)){
          
$id $row["id_menu"];
          
$list.= "<LI><A HREF='?id=$id'>".htmlspecialchars($row['title'])."</A>";
          
$sql "SELECT * FROM `menu` WHERE `pid`=$id";
          
//echo "(in): $sql<br>";
          
$r2 mysql_query($sql$link);
          if (
mysql_num_rows($r2) > 0
          
$list.= showTree($id);
          
$list.= "</li>\n";
     }
     if (
$parent_id!=0$list .= "</ul> <!-- parent = $parent_id -->\n";
}
ShowTree(0);
//print $list;
$smarty->assign('arr'$list);
$smarty->display("menu.tpl");

?>


Да, еще к этому меню стили добавляются и JS.
Как видно, я разбила вывод уровней на два запроса к базе. Один вытягивает родителей, другой - потомков. Вот у меня вопрос такой: если использовать два запроса, то какие в этом способе недостатки или преимущества по сравнению с одним запросом к базе, когда одним запросом вытягивается весь список. Что лучше два запроса или один?

   
 
 автор: Trianon   (04.07.2008 в 14:19)   письмо автору
 
   для: Лена   (04.07.2008 в 14:05)
 

в операторе if (mysql_num_rows($r2) > 0) что находится под условием?

   
 
 автор: Лена   (04.07.2008 в 14:25)   письмо автору
 
   для: Trianon   (04.07.2008 в 14:19)
 

Не совсем поняла вопрос. Если в базе есть ряды-потомки, то они выводятся и записываются в переменную, которая потом идет в шаблон: $list.= showTree($id);

   
 
 автор: Trianon   (04.07.2008 в 14:29)   письмо автору
 
   для: Лена   (04.07.2008 в 14:25)
 

>Не совсем поняла вопрос. Если в базе есть ряды-потомки, то они выводятся и записываются в переменную, которая потом идет в шаблон: $list.= showTree($id);

Вот именно. = showTree($id);
Это означает, что функция showTree ПО идее должна уметь возвращать хоть какой-то результат.
Где в Вашей функции хоть один оператор return?

   
 
 автор: Лена   (04.07.2008 в 14:39)   письмо автору
 
   для: Trianon   (04.07.2008 в 14:29)
 

Нет. Можно и по-другому. Если переменная объявляется как глобальная, то возвращать из функции ничего не надо. Результат автоматически записывается в эту переменную. И return тогда не нужно.
У меня в начале было так:
global $link, $smarty, $list;
Результат записывается в $list
Так sim5 меня учил.

   
 
 автор: Trianon   (04.07.2008 в 14:48)   письмо автору
 
   для: Лена   (04.07.2008 в 14:39)
 

Всё правильно говорите.
Но тогда и присваивать результат функции не следует. Результата-то нет?
Вместо $list .= showTree($id); нужно написать просто showTree($id);

   
 
 автор: sim5   (04.07.2008 в 15:32)   письмо автору
 
   для: Trianon   (04.07.2008 в 14:48)
 

Позволю небольшое пояснение. Лена обратилась ко мне по Скайп, что лучше два или один запрос к базе. Ответив, что лучше конечно один, а посмотрев что формирует код, предположил, что второй запрос делается для того, чтобы узнать - если у полученного из первого запроса id потомки, так как от этого будет зависить, какие указывать стили (или id объектов) для элементов меню (вложенность). Вот я и посоветовал описать все это на форуме, тем более, что есть на нем философ MySQL (на вопрос кто это, я назвал вас Trianon:)), который не только грамотно объяснит достоинства, поможет не просто составить запрос, но и объяснит суть процесса. А вы на разных языках начали...))

   
 
 автор: Trianon   (04.07.2008 в 15:51)   письмо автору
 
   для: sim5   (04.07.2008 в 15:32)
 

Значит пример (04.07.2008 в 14:05) был неполон?

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

   
 
 автор: sim5   (04.07.2008 в 16:29)   письмо автору
 
   для: Trianon   (04.07.2008 в 15:51)
 

Полон или нет был пример, сказать не могу. Я не видел CSS для меню, но мне показали пример HTML-кода меню:

<div class="suckerdiv">
<ul id="suckertree1">
<li><a href="#">Главная</a></li>
  <ul>
  <li><a href="#">JavaScript</a></li>
    <ul>
    <li><a href="#">PHP 4</a></li>
    </ul>
  </li>
</ul>
</li>
<li><a href="#">CSS</a></li>
</ul>
</div>

И если все так, то думается, достаточно будет добавить аргументом функции еще и уровень вложения, по которому определять вложенность. В противном случае (как я понимаю) требуется запросом узнавать не только, что pid=parent, но и есть ли категории с id равными pid, то есть - имеет ли запрашиваемая категория потомков.

   
 
 автор: Trianon   (04.07.2008 в 17:04)   письмо автору
 
   для: sim5   (04.07.2008 в 16:29)
 

Вот в этом примере 4-я снизу строка </li> явно чужая. Во всяком случае соответствующего открывающего тега я не нашел.

Уровень вложенности необязательно передавать параметром.
Его можно посчитать в статической переменной.

ShowTree()
{
static $level=0;
++$level;
.....
ShowTree()
....
--level;
return $list;
}

   
 
 автор: sim5   (04.07.2008 в 17:29)   письмо автору
 
   для: Trianon   (04.07.2008 в 17:04)
 

Нет, закрывающие теги элементов LI на месте - это родительские элементы. Картина немного прояснилась - я увидел JS и CSS. Нужно формировать в функции уровень, проверять его, формируя родительские элементы UL и LI. Этого должно хватить. Иначе суть вопроса в объедении в одном запросе - получить pid равное parent, одновременно узнавая есть ли у этого id потомки. В общем я так все понял.

   
 
 автор: Trianon   (04.07.2008 в 18:14)   письмо автору
 
   для: sim5   (04.07.2008 в 17:29)
 

Тогда может быть Вы мне это проясните?
<div class="suckerdiv">
<ul id="suckertree1">
<li><a href="#">Главная</a></li>
  <ul>
  <li><a href="#">JavaScript</a></li>
    <ul>
    <li><a href="#">PHP 4</a></li>
    </ul>
  </li>
</ul>
</li>
<li><a href="#">CSS</a></li>
</ul>
</div> 

Потому что я двух открывающих тэгов в этом коде не вижу

   
 
 автор: sim5   (04.07.2008 в 18:31)   письмо автору
 
   для: Trianon   (04.07.2008 в 18:14)
 

)) Это мой недосмотр, я сократил пример кода, оставив по одному родителю и их потомков, что бы покороче было, когда выставлял меню, потому так получилось.

   
 
 автор: Лена   (07.07.2008 в 09:28)   письмо автору
 
   для: sim5   (04.07.2008 в 18:31)
 

Код, преложенный Trianon`ом, работает нормально.
Но, если в функции формировать уровень, то получается вот что:

<?php
include("configs/dbopen.php");
require (
"smarty/Smarty.class.php");
$smarty = new Smarty;
function 
showTree($parent_id,$level) {
  global 
$link$list;
  
$sql "SELECT * FROM `menu` WHERE `pid` = "$parent_id ." ORDER BY `id_menu`";
  
//echo $sql."<br>";
  
$result mysql_query($sql) or die (mysql_error());
  
if (
$level && mysql_num_rows($result) > 0) {
     
$ulopn "<ul>";
     
$ulcls "</ul></li>";
     
$list substr($list0, -5);
  } else 
$ulopn $ulcls "";
  
$list .= $ulopn;
  while (
$row mysql_fetch_row($result)) {
  
$list.= "<li><A HREF=\"?id=$row[0]\">".htmlspecialchars($row[2])."</A></li>";
  
showTree($row[0],$level++);
  }
  
  
$list .= $ulcls;

}

//$list = "<div class='suckerdiv'>";
//$list .= "<ul id='suckertree1'>";
showTree(0,0);
//$list .= "</ul>";
//$list .= "</div>";
$smarty->assign('arr'$list);
$smarty->display("menu1.tpl");
?>

При этом содержимое выводится следующим образом(на вот таких уровнях):
Пункт1
Пункт1.1.
Пункт 1.2.
Пункт 2
Пункт 3
Пункт 3.1.
Пункт 3.2
А надо, чтобы Пункт1.1 и Пункт 1.2 выпадали, как и Пункт 3.1, Пункт 3.2. Получается стиль не срабатывает для потомков Пункта 1.
Где ошибка?

   
 
 автор: Trianon   (07.07.2008 в 11:37)   письмо автору
 
   для: Лена   (07.07.2008 в 09:28)
 

а) Вместо showTree($row[0],$level++); нужно написать showTree($row[0],$level+1);
б) в строках $ulopn = "<ul>";
$ulcls = "</ul></li>";
Вы почему-то готовитесь открыть один тег , а закрыть - два.

   
 
 автор: Лена   (07.07.2008 в 12:34)   письмо автору
 
   для: Trianon   (07.07.2008 в 11:37)
 

Если у нас есть вложенные элементы, то у элемента-родителя вырезаем substr() закрывающий тэг LI:
$list = substr($list, 0, -5);
Если вложения идут, например, вот так:
<li><ul>
<li></li>
<li></li>
</ul>
получается, что родительский элемент LI все еще открыт (потому как мы вырезали substr() конечный тэг). Поэтому надо его закрыть, у меня это: $ulcls = "</ul></li>"; Поэтому в случае вложений открывается один тэг, а закрывается - два. Если же мы имеем дело с родителем, то конечный LI не вырезается.

   
 
 автор: Trianon   (07.07.2008 в 12:51)   письмо автору
 
   для: Лена   (07.07.2008 в 12:34)
 

Всё равно это не повод, так над тегами издеваться.
Вот:
<?php
include("configs/dbopen.php");
require (
"smarty/Smarty.class.php");
$smarty = new Smarty;
function 
showTree($parent_id,$level
{
  global 
$link$list;
  
$sql "SELECT * FROM `menu` WHERE `pid` = "$parent_id ." ORDER BY `id_menu`";
  
//echo $sql."<br>";
  
$result mysql_query($sql) or die (mysql_error());
  
  if (
$level && mysql_num_rows($result) > 0
  {
     
$ulopn "<ul>";
     
$ulcls "</ul>";
  } else 
$ulopn $ulcls "";
  
$list .= $ulopn;
  while (
$row mysql_fetch_row($result)) 
  {
    
$list.= "<li><A HREF=\"?id=$row[0]\">".htmlspecialchars($row[2])."</A>";
    
showTree($row[0],$level+1);
    
$list.="</li>";
  }
  
$list .= $ulcls;
}

//$list = "<div class='suckerdiv'>";
//$list .= "<ul id='suckertree1'>";
showTree(0,0);
//$list .= "</ul>";
//$list .= "</div>";
$smarty->assign('arr'$list);
$smarty->display("menu1.tpl");
?>

   
 
 автор: Лена   (07.07.2008 в 12:59)   письмо автору
 
   для: Trianon   (07.07.2008 в 12:51)
 

Пути решений могут быть разными. Спасибо за все.

   
 
 автор: Trianon   (04.07.2008 в 14:24)   письмо автору
 
   для: Лена   (04.07.2008 в 14:05)
 

Тот же код с одним запросом.
<?php
include("configs/dbopen.php");
require (
"smarty/Smarty.class.php");
$smarty = new Smarty;
function 
ShowTree($parent_id)
{
  global 
$link;
  
$list '';
  
$sql "SELECT * FROM `menu` WHERE `pid` = "$parent_id ." ORDER BY `id_menu`";
//echo "(st): $sql<br>";
  
$result mysql_query($sql$link);
  if(
mysql_num_rows($result))
  {
     if (
$parent_id!=0$list .= "<ul> <!-- parent = $parent_id -->\n";
     while (
$row mysql_fetch_assoc($result))
     {
          
$id $row["id_menu"];
          
$list.= "<LI><A HREF='?id=$id'>".htmlspecialchars($row['title'])."</A>";
          
$list.= showTree($id);
          
$list.= "</li>\n";
     }
     if (
$parent_id!=0$list .= "</ul> <!-- parent = $parent_id -->\n";
  }
  return 
$list;
}
$list ShowTree(0);
//print $list;
$smarty->assign('arr'$list);
$smarty->display("menu.tpl");

?>

Касательно достоинств /недостатков:
Нагрузка на БД в два раза меньше.
Затрачиваемый php объем памяти меньше.
Код проще.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования