Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Вывод данных из БД в несколько колонок (каталог)
Форумы портала PHP.SU » » Работа с СУБД » Вывод данных из БД в несколько колонок (каталог)

Страниц (1): [1]
 

1. unambigos - 09 Декабря, 2011 - 14:44:20 - перейти к сообщению
Всем привет, сегодня написал скрипт вывода данных из БД в несколько колонок. Все отлично работает, но скрипт очень сложен в плане выборки из БД внутри цикла, т.е. очень много обращений к базе. Хотелось бы лишить скрипт такого недостатка.

CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. <style>
  3. .column{
  4.    float:left;
  5.    margin-right: 30px;
  6.    width: 300px;
  7. }
  8.  
  9. .column ul{
  10.    list-style-type: none;
  11.    background: #f6f6f6;
  12.    border: 1px dotted gray;
  13.    padding:5px;
  14. }
  15. </style>
  16.  
  17. <?php
  18.  
  19. //подключение к базе
  20. @mysql_connect("localhost","12345","12345") or die("Ошибка подключения к базе MySQL!");
  21. @mysql_select_db("example") or die("Ошибка подключения к базе данных");
  22.  
  23. //выборка пунктов 1-го уровня каталога
  24. @$res1 = mysql_query("SELECT id FROM catalog WHERE parent=0");
  25. @$myarray1 = mysql_fetch_array($res1);
  26.  
  27. $num = 0;
  28.  
  29. //цикл подсчета общего количества записей 2-го уровня
  30. do
  31. {
  32.    @$res3 = mysql_query("SELECT id FROM catalog WHERE parent='".$myarray1['id']."'");
  33.    $num += mysql_num_rows($res3);        
  34. }
  35. while ($myarray1= mysql_fetch_array($res1));
  36.  
  37. //опять выборка пунктов 1-го уровня каталога
  38. @$res = mysql_query("SELECT id,name FROM catalog WHERE parent=0");
  39. @$myarray = mysql_fetch_array($res);
  40.  
  41. $cols = 2; //число колонок
  42. $str = ceil($num/$cols); //округление в большую сторону числа строчек в одной колонке
  43. $j = 0; //обнуление счетчика
  44. for($i=1;$i<=$cols;$i++) //цикл счетчика колонок
  45. {
  46.  
  47.    
  48.    $content = "<div class='column'>";
  49.        //цикл вывода пунктов 1-го уровня каталога
  50.        do
  51.        {
  52.            
  53.            
  54.            $content.="<h3>".$myarray['name']."</h3><ul>";
  55.            @$res2 = mysql_query("SELECT name FROM catalog WHERE parent='".$myarray['id']."'");
  56.            @$myarray2 = mysql_fetch_array($res2);
  57.  
  58.                 //цикл вывода пунктов 2-го уровня каталога
  59.                do
  60.                {  
  61.                    if($myarray['id']){
  62.                   $content.="<li>".$myarray2['name']."</li>";
  63.                   $j++;
  64.                   }
  65.                }
  66.                while($myarray2 = mysql_fetch_array($res2));
  67.            $content.="</ul>";
  68.          
  69.        }
  70.        while($myarray = mysql_fetch_array($res) AND $j<$str);
  71.        
  72.    $content.="</div>";
  73.    if($str<$num)$str+=ceil($num/$cols);        
  74.    
  75.    echo $content;
  76. }
  77.  
  78.  
  79. ?>
  80.  



Пробовал использовать в цикле подсчета общего количества записей 2-го уровня запись вида SELECT COUNT(*) FROM catalog WHERE parent=.$myarray1['id']. - не работает, считает непонятно чего, но точно не количество записей.

Таблица в БД имеет следующий вид: /id/name/parent все записи каталога хранятся в ней где в поле parent указан id родительского элемента.

Есть предположение что вместо запросов внутри цикла нужно использовать конструкцию inner join. Но я перешарил весь интернет и так и не нашел руководства как этой конструкцией пользоваться. Я новичек в этих делах, так что сильно не ругайте. Надеюсь на Ваш профессионализм и помощь.
2. caballero - 09 Декабря, 2011 - 15:32:07 - перейти к сообщению
Цитата:
нужно использовать конструкцию inner join.

это просто join. по сути то же что в where таблицы перевязать

Цитата:
Я новичек в этих делах, так что сильно не ругайте

нет ничего дебильнее подобной фразы на форумах


если по существу - классическая проблемма выборки иерапррхических данных

по уму - надо добавлять дополнительные поля с уровнями вложености или иписком парентов с строке

В твоем случае лучше всего выгрести простым селектом всю таблицу в массив а потом бегать по нему тем же циклом
Не очень гармоничное решение но все же лучше чем ходить циклом к БД.
3. unambigos - 09 Декабря, 2011 - 15:48:35 - перейти к сообщению
По поводу извлечь все данные в массив, я тоже уже думал, ну это ладно когда записей 500, а когда их 50000? Сможет ли выборка перебором массива обеспечить нужное быстродейтвие? Тем более, что с разными условиями его несколько раз прогонять нужно будет?

Цитата:
по уму - надо добавлять дополнительные поля с уровнями вложености или иписком парентов с строке


Можешь подробнее об этом. Мысль такая была, но потом я подумал, а как эту вложенность высчитывать потом, когда он будет может 8-12 пунктов, не будешь же всю таблицу штудировать. Блин, а так мысль хорошая извлечь все поля с уровнем вложенности 2 например. А потом полученный массив уже циклами мучить? Правильно я понял?
4. unambigos - 10 Декабря, 2011 - 10:25:53 - перейти к сообщению
И кстати, кто нибудь может объяснить как пользоваться конструкцией JOIN. Или ссылочку, где написано как пользоваться. Только не для объединения разных таблиц, а для выборки из одной.
5. EuGen - 10 Декабря, 2011 - 10:28:33 - перейти к сообщению
Не путайте union и join

http://mysql[dot]ru/docs/man/UNION[dot]html
6. unambigos - 10 Декабря, 2011 - 11:38:34 - перейти к сообщению
EuGen, нет, это помоему не то, вот инфа с Хабра, кторая меня и заставила засомневаться

Цитата:
взяв на вооружение простое правило — «никогда не выполнять запросы в цикле». Примеры того, как это можно сделать:

1. Выборки
$news_ids = get_list('SELECT news_id FROM today_news ');
while($news_id = get_next($news_ids))
$news[] = get_row('SELECT title, body FROM news WHERE news_id = '. $news_id);

Правило очень простое — чем меньше запросов, тем лучше (хотя из этого, как и из любого правила, есть исключения). Не забывайте про конструкцию IN(). Приведенный код можно написать одним запросом:
SELECT title, body FROM today_news INNER JOIN news USING(news_id)


Только вот беда, пример приведен, а я понять ничего не могу и нигде нормальной информации нет, которая могла бы мне помочь понять это.
7. EuGen - 10 Декабря, 2011 - 14:25:43 - перейти к сообщению
unambigos пишет:
Только не для объединения разных таблиц, а для выборки из одной.

По-другому это сложно понять.
Сформулируйте точно, что Вам нужно. Почитайте отдельно про join и union - поймете разницу.
8. unambigos - 11 Декабря, 2011 - 11:45:38 - перейти к сообщению
EuGen, прочитал, немного вкурил, но не пойму как объединения таблиц могут мне помочь, таблица у меня одна. Мне необходимо избавиться от запросов к базе в цикле. Это при величине каталога в 300 позиций всего например 30 позиций 1-го уровня и по 10 позиций 2-го на каждый из 30, будет 40 запросов к базе при загрузке каталога. А если позиций намного больше? Вот и надо придумать как обойтись несколькими нестандартными запросами вне цикла. Вчера пробовал добавить поле уровня вложенности. Двумя запросами создал 2 массива с пунктами 1 уровня и с пунктами 2 уровня. И с помощью 2х циклов и условия вывести их. Но ничего не получилось. Позже выложу код, может я что нибудь не так делаю?
9. tuareg - 11 Декабря, 2011 - 12:08:52 - перейти к сообщению
Я так понял Вам надо вывести дерево каталогов. На форуме поищите есть темы.
А так выдергивайте всю таблицу в массив и сортируйте его как Вам надо
10. unambigos - 11 Декабря, 2011 - 17:54:46 - перейти к сообщению
Вот код, который призван работать с массивами для вывода каталога. НО он не работает, скажите где ошибка?

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

ПУНКТ 1 ПУНКТ 2
пункт1.1 пункт2.1
пункт1.2 пункт2.2
пункт1.3 пункт2.3

А вот код, который ниже выводит только:

ПУНКТ 1 ПУНКТ 3
пункт1.1
пункт1.2 ПУНКТ 4
пункт1.3

ПУНКТ 2

Не пойму в чем проблема, чисто логически все должно работать((



CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. <?php
  3.  
  4. @mysql_connect("localhost","12345","12345") or die("Ошибка подключения к базе MySQL!");
  5. @mysql_select_db("example") or die("Ошибка подключения к базе данных");
  6.  
  7. @$res = mysql_query("SELECT id,name FROM catalog WHERE parent=0");//выборка пунктов 0 уровня вложенности
  8. @$myarray = mysql_fetch_row($res);  
  9.  
  10. @$res2 = mysql_query("SELECT id,name,parent FROM catalog WHERE inv='1'");//выборка пунктов 1 уровня вложенности
  11. $num = mysql_num_rows($res2);//подчсчет количества
  12. @$myarray2 = mysql_fetch_array($res2);
  13.  
  14. $cols = 2;
  15. $str = ceil($num/$cols);
  16. $j = 0;
  17.  
  18. for($i=0;$i<=$cols;$i++)
  19. {
  20.    $content = "<div class='column'>";
  21.        while($myarray = mysql_fetch_array($res) AND $j<=$str)//вывод пунктов 0 уровня вложенности
  22.        {
  23.            $content.="<h3>".$myarray['name']."</h3><ul>";
  24.                while($myarray2 = mysql_fetch_array($res2))//вывод пунктов 1 уровня вложенности
  25.                {  
  26.                    if($myarray['id']==$myarray2['parent'])
  27.                    {
  28.                        $content.="<li>".$myarray2['name']."</li>";
  29.                        $j++;      
  30.                   }
  31.                }  
  32.            $content.="</ul>";
  33.        }    
  34.    $content.="</div>";
  35.    if($str<$num)$str+=ceil($num/$cols);    
  36.    echo $content;  
  37. }
  38. ?>
11. unambigos - 13 Декабря, 2011 - 11:00:52 - перейти к сообщению
Почему никто не хочет мне помочь Огорчение Почему код предыдущего поста выводит такую охинею?
12. Panoptik - 13 Декабря, 2011 - 11:11:56 - перейти к сообщению
напишите лучше структуру вашей базы и что вы хотите получить, так будет больше шансов получить вразумительный ответ, чем перебирать некорректно написанный код
13. unambigos - 13 Декабря, 2011 - 14:19:03 - перейти к сообщению
Panoptik

Есть таблица category в базе под названием example

Она имеет следующий вид
id/name/parent
1/Телефоны/0
2/Ноутбуки/0
3/Компьютеры/0
4/LG/1
5/Nokia/1
6/HP/2
и т.д

где поле parent имеет значение id родителя, находящеголся в этой же таблице

Требуется вывести данные из базы данных (каталог, дерево каталогов кому как нравится) в произвольное число колонок, ну например в 3 колонки. Чтобы сначала шли заголовки <h3>Родитель с parent=0</h3> <ul><li>Список детей</li></ul>. Результат приблизительно отображено на сайте slando.ru.
14. Panoptik - 13 Декабря, 2011 - 15:12:13 - перейти к сообщению
я часто применяю подобные функции при построении меню, хотя предпочитаю пользоваться дивами, а не списками, но логика всё равно остается та же:
PHP:
скопировать код в буфер обмена
  1.  
  2. function get_tree($parent,$level) {
  3.   $level++;
  4.   $query = "SELECT * FROM `category` WHERE `parent` = ".$parent;
  5.   $result = mysql_query($query);
  6.   if(mysql_num_rows($result)) {
  7.     print "<ul>";
  8.     while($row = mysql_fetch_assoc($result)) {
  9.       print "<li>";
  10.       print "<h".$level.">".$row['name']."</h".$level.">";
  11.       //здесь можно всунуть проверку на то есть ли в данной категории дочерние элементы. но в данном случае я обойдусь грубо без проверки, просто выведу пустые теги если никого нет
  12.       get_tree($row['id'],$level);
  13.       print "</li>";
  14.     }
  15.     print "</ul>";
  16.   }
  17. }
  18.  
  19. //вызов функции в таком виде:
  20. get_tree(0,0);
  21.  


писал на колене, так что не судите строго
15. unambigos - 13 Декабря, 2011 - 17:53:25 - перейти к сообщению
Panoptik Спасибо большое, все работает, я в восторге!!! Только не пойму, зачем нужна переменная $level?


Все понял, она нужна для понижения уровня заголовков. Осталось только подумать как ее остановить на 1м уровне вложенности, чтобы она не выводила сразу весь каталог

 

Powered by ExBB FM 1.0 RC1