webew
Войти » Регистрация
 
PHP
MySQL/MariaDB

Выборка из таблицы

22 марта 2010, 16:38
Автор: Sergey666777
Добрый день!
Опыта работы с таблицами практически нет.
помогите разобратся
Есть две таблицы mySQL.
tab1:

id catname
1 кат-1
2 кат-2
n кат-n

tab2:
id User URL opis category
1 user-1 http://1 любой текст 1
1 user-1 http://11 любой текст 1
2 user-2 http://2 любой текст 2
n user-n http://n любой текст n
Во второй таблице значение category равно id первой таблицы
Задача такая: создать страницу так чтоб на ней были наименования категорий (из столбца catname tab1). после клика на которые открывается вторая страница сформированная на базе tab2 на которой отображены ссылки только этой категории.
т.е. на первой странице:
кат-1
кат-2
кат-n
кликаю на кат-1 попадаю на страницу где вижу
http://1 любой текст
http://11 любой текст
Заранее благодарен за ответ.
Добавить комментарий
Отображение комментариев: Древовидное | Плоское

1234ru

Для начала Вам нужно определиться с видом ссылок.
Например, ссылки категории имеют вид http://ваш_сайт/id_категории - т.е.
http://ваш_сайт/1, http://ваш_сайт/2, ... и т.п.
(лучше пользоваться относительными ссылками, т.е. без http://ваш_сайт - /1, /2 ...)

Для страниц, относящихся к категории, в таблице лучше хранить не весь URL, а только ту его часть, которая отвечает за данную запись. Тогда ссылка на страницы, относящиеся к категориям, примут такой вид:
/id_категории/URL1
/id_категории/URL2
...

Чтобы вывести список ссылок категорий, нужен примерно такой код:

// перед этим нужно соединиться с базой с помощью функции mysql_connect:
// http://php.net/manual/en/function.mysql-connect.php
// для этого надо знать имя пользователя на сервере БД, пароль и имя базы данных

$html = ''; // будущий HTML-код сохраним в специальную переменную
$query = "SELECT id, catname FROM tab1"; // это - строка запроса к серверу MySQL
$result = mysql_query($query); // собственно, делаем запрос и получаем некую ссылку на его результат
while ($row = mysql_fetch_assoc($result) ) {
    // разбираем результат запроса построчно
    // каждая запись (строка) таблицы будет по очереди содержаться в переменной $row
    $html .= "<a href=\"/$row[id]\">$row[catname]</a> <br/>";
    // дописали в HTML-код очередную строку
    // можно переходить к следующей
    // и т.д...
}

// после выполнения цикла переменная $html содержит нужный HTML-код страницы
// его можно, например, вывести на экран:
echo $html;


Для ссылок категории будет так:

$html = '';
$catid = 1; // ну или по-другому выбираете id категории
$query = "SELECT URL, opis FROM tab2 WHERE catid = $catid";
$result = mysql_query($query);
while ($row = mysql_fetch_assoc($result) ) {
    $html .= "<a href=\"/$catid/$row[URL]\">$row[opis]</a> <br/>";
}
echo $html;



Сделать так, чтобы те или иные ссылки работали - отдельная задача. Один из вариантов её реализации описан в этой статье.
То, что не убивает нас, делает нас инвалидами.
29.03.2010, 00:01
Ответить
NO USERPIC

sogdianacha

Здравствуйте,
У меня такая задача, которую никак не получается решить. Есть таблица списка коренных категорий вмести с дочерними категориями. А также есть таблица объявлений, которые связываются с таблицей категорий. Нужно чтобы мы смогли соединиться к 2 таблицам и подсчитать объявления, которые относятся и коренным и дочерним категориям и вывести количество (например, авто(49). В авто имеются скажем 3 подкатегорий, в которых хранятся объявления, а в самом коренном категории авто нет объявлений, а только подкатегории, в которых хранятся объявления. Необходимо, чтобы мы смогли подсчитать сколько объявлений в дочерних категориях и вывести их количество рядом с коренной категорией). Ниже приведен код, в котором никак не могу добиться ожидаемого результата. Прошу вас помочь с решением данного вопроса. Заранее спасибо.

<?
$GLOBALS['cccount'] = 0;
if (defined('JBCITY')) $GLOBALS['subQuery'] = ' AND city_id = '.JBCITY; else $GLOBALS['subQuery'] = '';
function listcat2($id,$sub){
  $categories = mysql_query("SELECT id, child_category, name_cat, en_name_cat FROM jb_board_cat WHERE root_category = $id ORDER by sort_index"); cq();
  while($category = mysql_fetch_assoc($categories)){
    $name_cat = (defined('JBLANG') && constant('JBLANG')=='en') ? $category['en_name_cat'] : $category['name_cat'];
    $count_ads = mysql_result(mysql_query("SELECT COUNT(id) from jb_board WHERE id_category='".$category['id']."' AND old_mess='old'".$GLOBALS['subQuery']), 0);cq();
    //if($sub=="2") $subclass="class=\"subclass\"";else $subclass="";
        echo "(".$count_ads.")";
     $GLOBALS['cccount'] = $GLOBALS['cccount'] + $count_ads;
     if($category['child_category']==1){listcat2($category['id'],$sub+1);}
  }
}

$categories = mysql_query("SELECT id, root_category, child_category, name_cat,en_name_cat,img FROM jb_board_cat WHERE root_category=0 ORDER by sort_index");  cq();
$num_rows = @mysql_num_rows($categories);
$count_field=round($num_rows/2);$td=0;
echo "<div style=\"float:left;width:50%;\" class=\"index_cat gray sm\">";
while($category = @mysql_fetch_assoc($categories)){
  $name_cat = (defined('JBLANG') && constant('JBLANG')=='en') ? $category['en_name_cat'] : $category['name_cat'];
  echo (@$category['img'])?"<img alt=\"".$name_cat."\" class=\"rootcatimg\" src=\"".$u."cat/".$category['img']."\" />":"";
$lastres = mysql_query("SELECT COUNT(id) FROM `jb_board` WHERE `id_category` IN (SELECT `id` FROM `jb_board_cat` WHERE `root_category` = $id)");
echo "<a class=\"rootcat\" href=\"c".$category['id'].".html\">".$name_cat."</a> (".$lastres.") ";
  $td++;if($td>=$count_field){echo "</div><div style=\"float:right;width:50%;\" class=\"index_cat gray sm\">";$td=0;}
}
echo "</div><div class=\"clear\"></div>";
?>

Вот тут ссылка на файл, который выводит список категорий и файл базы таблиц с запросом create: Пожалуйста, помогите с решением моей проблемы. Надеюсь на вашу помощь. Ссылка на файл: http://webew.ru/f/OE2REhKW.zip

Спасибо.
20.02.2012, 02:22
Ответить
NO USERPIC

rgbeast

Опишите пожалуйста какие именно проблемы с приведенным кодом и что не получается сделать.
21.02.2012, 23:54
Ответить
NO USERPIC

sogdianacha

Проблема в том что на странице категорий, должно отображаться список коренных категорий и рядом с каждым из них количество объявлений, которые находятся в подкатегории данной категории, например Главная категория -> Авто, а подкатегории -> Легковые, и ->Грузовые. В подкаталогах Легковые скажем 31 объявлений, а грузовых 49 объявлений.
На странице списка категорий например для случая категории АВТО должно отображаться общее кол-тво объявлений в скобках (80) и в итоге получается так: Авто(80). В данном случае, считывается общее кол-тво объявлений в подкатегории главной коренной категории. Вот этого и мне нужно добиться.
22.02.2012, 00:47
Ответить
NO USERPIC

vasya

Приложенный вами файл по указанной ссылке отсутствует.

Совершенно не понятно, что именно у вас не получается. Конкретизируйте проблему.
Из того, что бросается в глаза:

$lastres = mysql_query("SELECT COUNT(id) FROM `jb_board` WHERE `id_category` IN (SELECT `id` FROM `jb_board_cat` WHERE `root_category` = $id)");

mysql_query() возвращает указатель на результат запроса, или FALSE если запрос не был выполнен.
А следующей строчкой вы выводите на экран переменную $lastres, по всей видимости, ожидая получить число равное COUNT(id). Но для этого нужно обработать результат запроса одной из следующих функций:
mysql_fetch_array(), mysql_fetch_row(), mysql_fetch_assoc(), mysql_result().
22.02.2012, 03:46
Ответить
NO USERPIC

sogdianacha

Здравствуйте.
Я загрузила файлы на народ.ру вот ссылка: http://narod.ru/disk/41275169001.a8ed714476de8d19c6670d6c3c543b19/CAT.zip.html (сам файл который выводит список и create db.sql)

Проблема в том, необходимо вывести общее кол-тво объявлений рядом с коренной категории (коренная категория имеет подкатегории, в которых содержаться объявления).

В данном случае, делая такой запрос
$lastres = mysql_query("SELECT COUNT(id) FROM `jb_board` WHERE `id_category` IN (SELECT `id` FROM `jb_board_cat` WHERE `root_category` = $id)");
echo "<a class=\"rootcat\" href=\"c".$category['id'].".html\">".$name_cat."</a> (".$lastres.") ";

отображается undefined id

Пожалуйста, скачайте файлы, думаю, что будет более понятно. Спасибо.
22.02.2012, 04:19
Ответить

1234ru

vasya
Приложенный вами файл по указанной ссылке отсутствует.

Это, похоже, я нечаянно файл замочил.
Вернул, теперь ссылка рабочая.

Впрочем, проблему мы, в общем-то, решили.
То, что не убивает нас, делает нас инвалидами.
25.02.2012, 04:20
Ответить

1234ru

Перед Вами стоит довольно сложная задача, поэтому подготовка кода из имеющихся наработок потребует некоторого времени.
Надо Вам будет подождать дня два-три.
Тогда получите код со всеми необходимыми пояснениями, который сможете использовать для меню с любым уровнем вложенности.
От вашего он будет отличаться кардинально, но если Вы в нем разберетесь, у Вас вряд ли когда-либо вообще
возникнут проблемы с построением меню.
То, что не убивает нас, делает нас инвалидами.
22.02.2012, 05:15
Ответить
NO USERPIC

sogdianacha

Здравствуйте.
Спасибо за поддержку. Я Вам очень признательна.
23.02.2012, 00:46
Ответить

1234ru

Так.. Ну, вот для Вас код (пока без обещанных пояснений):

require_once 'mysql_functions.php';
require_once 'tree-builder.php';


# 1. Формируем SQL-запрос для получения данных меню из БД

$title_key = (defined('JBLANG') && constant('JBLANG')=='en')
             ? 'en_name_cat'
             : 'name_cat' ;
             
$sql = "
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count
    FROM jb_board_cat AS cat
    LEFT JOIN jb_board AS b ON cat.id = b.id_category
    "
.
        (
        defined('JBCITY')
        ? "WHERE b.city_id = " . JBCITY
        : ""
    ) . "
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.$title_key ASC
    "
;

$menudata = mysql_gettable($sql, 'id');
 // О mysql_gettable см. http://webew.ru/articles/3237.webew#mysql_gettable-text

 
# 2. Перестраиваем массив данных меню
#    в соответствии с его иерархической структурой

$T = new Tree_Builder;
$menutree = $T->make_tree($menudata, 'count');


# 3. Генерируем HTML-код блока меню

$HTML = '
    <style>
        .index_cat { float: left; width: 50%; }
        .index_cat a { display: block; }
    </style>
   
    <div class="index_cat gray sm">
    '
;

foreach ($menutree as $item) {
    $item['url'] = "c$item[id].html";
    $item['img_src'] = ($item['img'])
                       ? "cat/$item[img]"
                       : '' ;
    $item['class'] = ($item['parent_id'] != 0)
                     ? 'root'
                     : '';
    $HTML .= "
        <a
         $item[class]
         href=\"$item[url]\"
        >
        "
. (
                ($item['img'])
                ? "<img
                   src=\"$item[img_src]\"
                   alt=\"$item[$title_key]\"
                  >"

                : ""
            )
        . "
            $item[$title_key]
            ($item[count])
        </a>
        "
;
}

$HTML .= '</div>';

echo $HTML;


Должен давать то, что Вам требуется, если я всё правильно понял,
Вам понадобятся два файла, которые Вы можете скачать здесь - mysql_functions.php и tree-builder.php.

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

Вопросы советую разбить на три группы:

- SQL-запрос
- Работа с данными меню
- HTML-код и стили
То, что не убивает нас, делает нас инвалидами.
24.02.2012, 22:47
Ответить
NO USERPIC

sogdianacha

Здравствуйте 1234ru,

Я очень благодарна Вам за Вашу помощь и поддержку. Я очень Вам признательна за все, что Вы делаете для меня. Я скопировала весь код и скачала 2 файла mysql_functions.php и tree-builder.php.
Попробую разобраться в кодах. Конечно я новичок в этом деле, но постараюсь по максимуме. Но если у я не разберусь, то буду поэтапно задавать вопросы.
Еще раз Вам спасибо.
25.02.2012, 02:53
Ответить

1234ru

Советую начать с mysql_functions.php. Почитайте вот эту статью - http://webew.ru/articles/3237.webew.
Эти функции пригодятся Вам и в дальнейшем, ведь наверняка Вы будете работать с MySQL (сам код функций можно не разбирать, достаточно понять, как ими пользоваться, для этого нужно просто прочитать статью).

Успехов!
То, что не убивает нас, делает нас инвалидами.
25.02.2012, 04:18
Ответить
NO USERPIC

sogdianacha

Спасибо. Сохранила статью по ссылке http://webew.ru/articles/3237.webew. Обязательно прочитаю и воспользуюсь Вашими советами. Спасибо.
25.02.2012, 04:54
Ответить
NO USERPIC

sogdianacha

Здравствуйте,

Вчера начала изучать коды. В действительности, очень сложно. Многое я не поняла. Начиная sql запроса. Например, вот эти строки:
1. SUM(IF(b.old_mess = 'old', 1, 0)) AS count
2. LEFT JOIN jb_board AS b ON cat.id = b.id_category (а откуда берется b и что означает b ?

Если Вы не против, пожалуйста, прокомментируйте sql запрос.
Да, кстати, я скопировала 2 mysql_functions.php и tree-builder.php в ту директорию, а сам код поместила в файл, который должен отображать список коренных категорий (удалила код, который был ранее).

После того, как сохранила, система выдает такое сообщение: undefined function print_pre on line 36 in tree-builder.php

Спасибо. Буду ждать Ваших комментарий.
26.02.2012, 03:22
Ответить

deadka

LEFT JOIN jb_board AS b
b - просто синоним jb_board, то есть b.id_category - то же самое, что и jb_board.id_category

SUM(IF(b.old_mess = 'old', 1, 0)) AS count
Если запись old_mess принимает значение old, то if возвращает 1, иначе 0. А весь результат будет называться count.


> После того, как сохранила, система выдает такое сообщение: undefined function print_pre on line 36 in tree-builder.php
Гхм. А покажите строки с 33-й по 48-ю в файле tree-builder.php
Что-то там не то написано.
Через more, через less мы бредем в страну чудес...
27.02.2012, 00:25
Ответить
NO USERPIC

sogdianacha

Здравствуйте.
Спасибо за Ваш ответ.
Вот содержание файле tree-builder.php:

<?php

Class Tree_Builder {

function make_tree($data, $sumkey = FALSE) {
// Принимает массив вида [id] => [данные].
// Возвращает те же данные,
// где элементы расположены
// согласно древовидной структуре
// (КЛЮЧИ СОХРАНЯЮТСЯ):
//
// [1] => A ( id = 1, level = 1)
// [2] => B (id = 2, parent_id = 1, level = 2)
// [3] => C (id = 3, parent_id = 1, level = 2)
// [5] => C.1 (id = 5, parent_id = 3, level = 3)
// [27] => C.2 (id = 6, parent_id = 3, level = 3)
// [34] => C.3 (id = 7, parent_id = 3, level = 3)
// [9] => D (id = 8, parent_id = 1, level = 2)
// [15] => E (id = 15, level = 1)
// [16] => F (id = 16, parent_id = 15, level = 2)
// ...
// В данные добавляется ключ level,
// в который записывается
// уровень иерархии текущего элементы
// (уровни начинаются с первого, к которому
// принадлежат элементы с parent_id = 0)
$children = $this->list_children($data);
$tree_ids = $this->tree_ids($children);
$tree_data = $this->tree_data($data, $tree_ids);
if ($sumkey)
$tree_data = $this->aggregate($tree_data, $sumkey);
return $tree_data;
}

function aggregate($tree_data, $sumkey) {
print_pre($tree_data);
end($tree_data);
$sum = 0; $parent_id = 0;
while( ! is_null($key = key($tree_data))) {

$current = current($tree_data);

if (!isset($current[$sumkey]))
$current[$sumkey] = 0;

$parent_id = $current['parent_id'];

if (isset($tree_data[$parent_id])) {
if (!isset($tree_data[$parent_id][$sumkey]))
$tree_data[$parent_id][$sumkey] = 0;

$tree_data[$parent_id][$sumkey] += $current[$sumkey];
}

prev($tree_data);
}

print_pre($tree_data);
return $tree_data;
/*
foreach ($children as $id => $ch) {
$child_data = $tree_data[$id];
if (isset($data[$sumkey]) OR !$data[$sumkey]) {
$data[$sumkey] =
}
else
$tree_data[$id][$sumkey] += $data[$sumkey];
}
*/
}

function list_children($data) {
// Поиск прямых потомков
// для каждой из записей
// (у которой потомки есть)
// плюс корневые элементы (parent_id = 0)
// возвращается в виде массива:
// [0] => Array(1,15)
// [1] => Array(2,3,9)
// [2] => Array(5,27,34)
// [15] => Array(16, ...)
// ...

$children = array();
foreach ($data as $row) {
$children[$row['parent_id']][] = $row['id'];
}
return $children;
}

function tree_ids($children, $parent_id = 0, $level = 1) {
// возвращает список элементов
// в иерархической последовательности
// в виде массива [id] => [level]
// (т.е. id - В КЛЮЧАХ!)
$tree_ids = array();
$F = __FUNCTION__;

if (
isset($children[$parent_id])
AND
$siblings = $children[$parent_id]
) {

foreach ($siblings as $id) {
$tree_ids[$id] = $level;

$tree_ids = // именно оператор +, а не array_merge(),
$tree_ids // т.к. она уничтожает числовые ключи
+
$this->$F($children, $id, $level + 1) ;
}
}

return $tree_ids;
}

function tree_data($data, $tree_ids) {
$tree_data = array();
foreach ($tree_ids as $id => $level) {
if (isset($data[$id])) {
$row = compact('level') + $data[$id];
$tree_data[$id] = $row;
}
}
return $tree_data;
}
}

?>
А также, Вы можете скачать по ссылке данный файл по ссылке: http://webew.ru/f/JDyH4TRH.php .Спасибо.
27.02.2012, 01:47
Ответить

deadka

Хм, в приведенном файл tree-builder.php действительно отсутствует метод print_pre.
Закомментарьте вызовы этого метода для начала (ну или создайте метод с такими именем, но пустой), позже найдём его.
Через more, через less мы бредем в страну чудес...
27.02.2012, 02:03
Ответить
NO USERPIC

sogdianacha

Я заменяла print_pre на print. Но в данном случае, отобразились корневые категории с подкатегориями. А также вывел сообщение Array/Array.
Попробую закомментировать ту строку. Спасибо.
27.02.2012, 02:35
Ответить

deadka

есть еще вероятность, что
print_pre($data);
стоит заменить на
print "<pre>"; print_r($data); print "</pre>";
, попробуйте.
Через more, через less мы бредем в страну чудес...
27.02.2012, 02:54
Ответить
NO USERPIC

sogdianacha

ок. попробую так сделать. Может получится. очень надеюсь.
27.02.2012, 03:10
Ответить

1234ru

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

sogdianacha
После того, как сохранила, система выдает такое сообщение: undefined function print_pre on line 36 in tree-builder.php

Пардон, это я свою отладочную функцию забыл убрать. Файл закачал заново, ссылку на файл в своем ответе заменил.
Скачайте обновленный файл или просто уберите все упоминания функции print_pre.
Ну, или еще вариант есть - добавьте в код функцию print_pre :)

function print_pre($var, $no_echo = FALSE) {
    $print = (is_array($var))
         ? "<pre>" . print_r($var, 1) . "</pre>"
         : "<pre>$var</pre>" ;
   
    if (!$no_echo)
        echo $print;
   
    return $print;
}


(если смотрите результаты в браузере, ее несколько удобней использовать - возьмите любой массив и выведите на экран с помощью print_r, а затем с помощью print_pre - будет видна разница).


Насчет SQL-запроса.
Скажите-ка вот что.. Знаете ли Вы, что такое (и зачем)
1) JOIN
2) GROUP BY
3) SUM
?
То, что не убивает нас, делает нас инвалидами.
27.02.2012, 12:10
Ответить
NO USERPIC

sogdianacha

Здравствуйте.
Спасибо что ответили.
Говоря о sql запросе:
$sql = "
SELECT
cat.id AS id,
cat.root_category AS parent_id,
cat.name_cat,
cat.sort_index,
cat.en_name_cat,
cat.description,
cat.img,
SUM(IF(b.old_mess = 'old', 1, 0)) AS count
FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category
" .
(
defined('JBCITY')
? "WHERE AND b.city_id = " . JBCITY
: ""
) . "
GROUP BY cat.id
ORDER BY cat.sort_index DESC, cat.$title_key ASC
";
было непонятно b. Может b это общепринятое значение в mysql? Смысл запроса я поняла, но сама вряд ли смогу составить такой сложный запрос. так как если я правильно поняла, то в начале дается указание на выборку схожих столбцов из 2 таблиц, объединить значения. А дальше чуть сложно прокомментировать. Если поясните, то надеюсь смогу уловить смысл. Пожалуйста, прокомментируйте данный запрос.

Говоря о print_pre (до прочтения Вашего ответа) , я закомментировала строки, которые содержат print_pre. В итоге получилось так:
На странице отобразилось все категории: коренные категории и подкатегории с кол-твом например Авто (34).
Классно получилось. Но хотелось бы, что отображались только коренные категории с общим кол-твом объявлений, которые содержатся в их подкатегориях. А после клика на коренной категории осуществлялся переход на подкатегорию.

Спасибо. Буду ждать Ваших комментариев.
28.02.2012, 02:39
Ответить

1234ru

sogdianacha
Говоря о sql запросе ... было непонятно b


b в данном случае - это так называемый псевдоним (alias) таблицы.
Когда в запросе упоминаются несколько таблиц, в общем случае необходимо указывать название таблицы перед именем столбца. Например:

SELECT
jb_board_cat.id,
jb_board_cat.root_category,
jb_board_cat.name_cat,
jb_board_cat.sort_index,
jb_board_cat.name_cat,
jb_board_cat.description,
jb_board_cat.img,
SUM(IF(jb_board.old_mess = 'old', 1, 0)) AS count
FROM jb_board_cat
LEFT JOIN jb_board ON jb_board_cat.id = jb_board.id_category
...


Чтобы каждый раз не писать полностью имена таблиц, им назначают короткие псевдонимы, которые можно использовать вместо имён. Псевдоним назначается в конструкциях FROM или JOIN (это может быть не вполне очевидно, т.к. в запросе они идут не первыми)
...
FROM jb_board_cat AS cat
JOIN jb_board AS b ...


AS можно опускать: FROM jb_board AS b - то же, что FROM jb_board b.

В качестве псевдонима можно использовать любую последовательность латинских букв и цифр, т.е. именно 'b' совершенно не принципиально.


Помимо псевдонимов таблиц есть также псевдонимы столбцов. Их назначение - переименование колонок в результатах запроса.
Обратите внимание на шапку таблицы результатов:
mysql> SELECT id FROM jb_board LIMIT 1;
+----+
| id |
+----+
| 32 |
+----+
...
mysql> SELECT id AS board_id FROM jb_board LIMIT 1;
+----------+
| board_id |
+----------+
|       32 |
+----------+

Псевдонимы столбцов также определяют значения ключей в ассоциативных массивах, получаемых с помощью встроенной функции PHP mysql_fetch_assoc() (и, как следствие, mysql_gettable(), mysql_getrow() и mysql_getcolumn() из mysql_functions.php):

print_r(mysql_getrow("SELECT id FROM jb_board LIMIT 1"));
Array
(
    [id] => 32
)


print_r(mysql_getrow("SELECT id AS board_id FROM jb_board LIMIT 1"));
Array
(
    [board_id] => 32
)


Для работы класса Tree_Builder нужно, чтобы элемент массива, содержащий id родительской категории, имел ключ 'parent_id', поэтому в запросе я указал колонке root_category.

Если столбец указан в запросе с использованием имени (или псевдонима) таблицы, назначение псевдонима столбцу происходит точно так же:
...
root_category AS parent_id
...


Следует отметить, что псевдонимы столбцов совершенно необходимы в том случае, если в результате запроса присутствуют колонки из разных таблиц, но с одинаковыми названиями (например, если бы нужны были одновременно jb_board.id и jb_board_cat.id) - чтобы их различить.

Псевдонимы столбцов также могут быть какими угодно.


Да, кстати. Когда приводите код - по возможности, пользуйтесь подсветкой синтаксиса (при написании ответа выделите код в текстовом поле, потом нажмите кнопочку Syntax над полем и там выберите язык).


Чуть позже прокомментирую остальные ваши вопросы.
То, что не убивает нас, делает нас инвалидами.
28.02.2012, 15:04
Ответить

1234ru

sodgianacha
Смысл запроса я поняла, но сама вряд ли смогу составить такой сложный запрос. так как если я правильно поняла, то в начале дается указание на выборку схожих столбцов из 2 таблиц, объединить значения.


Это т.н. JOIN - один из способов получить одни запросом данные из двух и более таблиц, используя связь между записями в них.

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

SELECT
  b.title,
  cat.en_name_cat
FROM jb_board b
JOIN jb_board_cat cat ON b.id_category = cat.id


Результат запроса будет содержать данные из разных таблиц: первая колонка - из таблицы с объявлениями, вторая - из таблицы с категориями

+------------------------------------+------------------+
| title                              | en_name_cat      |
+------------------------------------+------------------|
| Чипардаи супер                     | Жалюзи           |
| Видео дарсхо                       | Кухни на заказ   |
| Такси 24 часа                      | Такси            |
| Посольства Таджикистан зарубежом   | Кухни на заказ   |
| Пишу книги обо всем                | Жалюзи           |
...
+------------------------------------+------------------+


связь между таблицами - ON b.id_category = cat.id, т.е. для каждой записи из таблицы jb_board будет взято значение ячейки id_category; затем будет предпринята попытка найти такую запись (или записи) в jb_board_cat, которые содержат в ячейки id то же значение, что и исследуемая запись из jb_board - в ячейке id_category.
Каждая пара таких записей (пара - потому что две таблицы) будет представлять собой одну строчку в результате запроса.


Теперь о том, что такое LEFT JOIN.

Представьте себе ситуацию, в которой среди объявлений имеется такое, которому не соответствует ни одна категория из таблицы jb_board_cat (категории с указанным id не существуюет, или колонка id_category вообще не заполнена).
Вышеописанный JOIN (без LEFT) называется строгим, потому что он вернет только те записи, которым есть соответствие во всех указанных таблицах.
По этой причине такое "бесхозное" объявление в результат строгого JOIN не войдет.

Запись же вида
FROM jb_board b
LEFT JOIN jb_board_cat ON b.id_category = cat.id

означает буквально "взять все записи из таблицы jb_board, и попытаться подставить к ним записи из jb_board_cat согласно условию, указанному в ON; если это не получится - заполнить в результате запроса недостающие ячейки из jb_board_cat значениями NULL".

Таблица в FROM называется в таком случае главной, в LEFT JOIN - второстепенной.
При обычном JOIN разницы между главной и второстепенной нет.

Рассмотрим теперь обратную ситуацию - когда главной таблицей является таблица с категориями.
Если написать обычный JOIN (не LEFT), в результат запроса войдут только те категории, в которых есть объявления.
А нам нужны все. Поэтому нам необходим именно LEFT JOIN.

Результат запроса вида

SELECT
  cat.id,
  cat.en_name_cat,
  b.id AS message_id,
  b.title
FROM jb_board_cat cat
LEFT JOIN jb_board b ON b.id_category = cat.id;

будет выглядеть примерно вот так:

+-----+-------------------------------+------------+----------------------------------+
| id  | en_name_cat                   | message_id | title                            |
+-----+-------------------------------+------------+----------------------------------+
| 182 | Грузоперевозки по городу      |       NULL | NULL                             |
| 183 | Мебель на заказ               |         38 | Предлагаю услуги посредника      |
| 183 | Мебель на заказ               |         39 | Я Предлагаю услуги посредника    |
...  
| 184 | Юридические услуги и финансы  |         56 | klkllklkk                        |
| 185 | Обучение и репетиторство      |       NULL | NULL                             |
| 186 | Компьютеры и Интернет         |       NULL | NULL                             |
| 187 | Строительство и ремонт        |       NULL | NULL                             |
| 178 | Кухни на заказ                |         33 | Видео дарсхо                     |
...


Обратите внимание, что в некоторых строках ячейки, соответствующие таблице jb_board - message_id и title - содержат NULL.
Это именно те записи из jb_board_cat, соответствия которым в jb_board не нашлось.


О GROUP BY

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

Посмотрим, как будет выглядеть результат запроса, если его визуально разбить на группы по категориям:
+-----+-------------------------------+------------+------------------------------------+
| id  | en_name_cat                   | message_id | title                              |
+-----+-------------------------------+------------+------------------------------------+

| 182 | Грузоперевозки по городу      |       NULL | NULL                               |

| 183 | Мебель на заказ               |         38 | Предлагаю услуги посредника        |
| 183 | Мебель на заказ               |         39 | Я Предлагаю услуги посредника      |
| 183 | Мебель на заказ               |         44 | лорлор                             |
| 183 | Мебель на заказ               |         45 | defwfewq                           |
| 183 | Мебель на заказ               |         46 | S5 Accordion Menu                  |
| 183 | Мебель на заказ               |         49 | lksdsa                             |
| 183 | Мебель на заказ               |         50 | ждлв\ывсвыс всыв                   |
| 183 | Мебель на заказ               |         51 | wfwefewfefe                        |

| 184 | Юридические услуги и финансы  |         56 | klkllklkk                          |

| 185 | Обучение и репетиторство      |       NULL | NULL                               |

| 186 | Компьютеры и Интернет         |       NULL | NULL                               |

| 187 | Строительство и ремонт        |       NULL | NULL                               |

| 178 | Кухни на заказ                |         33 | Видео дарсхо                       |
| 178 | Кухни на заказ                |         34 | Посольства Таджикистан зарубежом   |
| 178 | Кухни на заказ                |         42 | ghhgghgghgh                        |
| 178 | Кухни на заказ                |         48 | ДВУЛАво                            |
| 178 | Кухни на заказ                |         55 | lawyer                             |
...
+-----+------------------------------------+------------+-------------------------------+


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

Сначала нам нужно указать MySQL, как формировать группу, т.е. что у записей группы общего.
Т.к. группы формируются по категориям, очевидно, общее у них - это id группы. Его и нужно указать: GROUP BY cat.id.
Обратите внимание, что указывается именно cat.id, а не b.id_category, т.к. в противном случае в выборку не попадут те категории, в которых нет объявлений.

(продолжение следует)
То, что не убивает нас, делает нас инвалидами.
29.02.2012, 01:12
Ответить
NO USERPIC

sogdianacha

Здравствуйте. Спасибо, что Вы уделяете для меня столько Вашего драгоценного времени. Я Вам очень признательна. Я восхищяюсь Вами. Вы столько чего знаете в веб программировании. Мне бы тоже как и Вы. Стараюсь освоить все, что Вы пишите тут. Тут все описано подробно. Буду ждать продолжений. Спасибо.
29.02.2012, 06:45
Ответить

1234ru

Теперь разберемся, для чего вообще бывает нужна группировка и как с ней работать.
Группировка обычно требуется, чтобы для каждой группы подсчитывать какое-нибудь общее значение. Например, общее количество записей в группе.

Собственно, именно это нам и было нужно - выяснить количество объявлений в каждой из категорий.
При группировке это можно сделать с помощью функции COUNT(), которой в качестве аргумента следует передать какой-нибудь из столбцов таблицы с объявлениями, в ответ она вернет количество записей в группе, у которых этот столбец не равен NULL (лучше всего - столбец с id, т.к. он не NULL точно, если объявление существует).
Вот так, например, выглядит запрос для получение id категории и количества объявлений:
SELECT
    cat.id,
    COUNT(b.id) AS count
FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category


Помимо COUNT есть еще функции SUM() - для подсчета суммы по столбцу, MIN()/MAX()/AVG() - получение минимального/максимального/среднего значения и др. (полный список - на сайте MySQL).

Следует отметить, что COUNT(b.id) - то же, что SUM( IF(b.id IS NOT NULL, 1, 0) ).

Тут сразу две незнакомых конструкции - IF() и IS NOT NULL.
Они просты. Функция IF() принимает три аргумента: первый - некое выражение (в т.ч. уже готовую величину; если указано имя столбца, то для каждой записи функции подставляется значение соотв. ячейки), второй - выражение (или, опять же, готовую величину, в примере выше - 1), значение которого следует вернуть, если первый аргумент - TRUE, и третий - то, что следует вернуть, если аргумент FALSE.

Конструкция вида "что-то" IS NOT NULL проверяет, является ли "что-то" NULL-величиной или нет (NULL - специальный тип данных в MySQL; с ним мы уже встречались при рассмотрении результатов LEFT JOIN).

Таким образом, IF(b.id IS NOT NULL, 1, 0) означает буквально "если b.id не содержит NULL, то 1, в противном случае - 0".


Неслучайно речь зашла о замене COUNT() на SUM(): перед нами ведь стоит несколько более сложная задача, чем просто подсчет записей.
Нужно подсчитать только записи, у которых поле old_mess содержит 'old'.
Тут-то нам и пригодится функция IF, с помощью которой подсчитать количество таких записей в каждой группе можно выражением
SUM(IF( b.old_mess = 'old', 1, 0)),
которое и присутствует в конечном запросе.
То, что не убивает нас, делает нас инвалидами.
01.03.2012, 01:51
Ответить

1234ru

sogdianacha
хотелось бы, что отображались только коренные категории с общим кол-твом объявлений, которые содержатся в их подкатегориях. А после клика на коренной категории осуществлялся переход на подкатегорию.


Другими словами, чтобы активная (просматриваемая в данный момент) категория был раскрыта (т.е. показаны дочерние), а кроме нее показаны только корневые (соответственно, если активного пункта нет, то чтобы отображались только корневые)?
То, что не убивает нас, делает нас инвалидами.
01.03.2012, 01:54
Ответить
NO USERPIC

sogdianacha

Цитата:
Другими словами, чтобы активная (просматриваемая в данный момент) категория был раскрыта (т.е. показаны дочерние), а кроме нее показаны только корневые (соответственно, если активного пункта нет, то чтобы отображались только корневые)?

Здравствйте. Почти что я хотела, только вот когда вы переходите с корневой категории к подкатегориям, отображаются только сама коренная категория и подкатегории, а остальные категории (коренные) не должны отображаться на странице подкатегорий, если данная подкатегория или подкатегории не относится к этой коренной категории.
Спасибо.
01.03.2012, 02:24
Ответить

1234ru

Тогда еще пара уточнений:

1. Если не выбрана ни одна категория, что показывается? Список корневых?

2. До какой глубины раскрывать дерево активной категории? На один уровень или до самого низа?
То, что не убивает нас, делает нас инвалидами.
01.03.2012, 20:51
Ответить
NO USERPIC

sogdianacha

Здравствуйте,

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

Второй пункт:
Дерево активной категории должен раскрываться на один уровень. То есть, при нажатии на корневой категории, должна открыться страница подкатегорий относящихся к той корневой категории с которой был переход. А при клике на один из подкатегорий открывается страница содержащая список объявлений относящихся к данной подкатегории.
Например,
эти корневые категории

Авто (25) кликаем тут
Интернет (45)
Магазины (34)
Компании (0)

открывается новая страница подкатегорий с:

Аренда машин (4)
Продажа машин (21)
Обмен машин (0)

Если кликаем на один из подкатегорий, например на Продажа машин (21), то открывается страница со списком объявлений.

Спасибо Вам за поддержку.
02.03.2012, 00:09
Ответить

1234ru

Такую задачу можно переформулировать как "вывести список подкатегорий активной категории, если активной категории нет - вывести список подкатегорий нулевой категории" (нулевой - с той точки зрения, что корневые категории имеют parent_id = 0).

Таким образом, Вам нужно как-то определить id активной категории или же установить, что активная категория не установлена.

Код может быть примерно следующим:

// допустим, определили id активной категории
// и записали в переменную
// если её нет, то - FALSE

$root_id = ($active_id) {
           ? $menutree[$active_id]['parent_id']
           : 0 ;

// дальше пойдем простым путем -  
// найдем нужные элементы перебором
$for_html = array();
foreach ($menutree as $row) {
    if ($row['parent_id'] == $root_id)
        $for_html[] = $row;
}


А затем следует просто сгенерировать HTML-код меню, как это описано в п. 3 комментария http://webew.ru/posts/2823.webew#4153, только вместо массива $menutree использовать полученный вышеуказанным способом $for_html.
То, что не убивает нас, делает нас инвалидами.
06.03.2012, 19:22
Ответить
NO USERPIC

sogdianacha

Здравствуйте.

Я хотела написать о результатах работы. У меня все таки не получилось вывести на главной странице список только коренных категорий.
Давайте сделаем так. Подкатегории мы не будем выводить на странице коренных категорий. Для отображения подкатегорий, я использую другой php файл. Главное нам нужно сделать так чтобы на главной отображались только коренные категории с общим кол-твом объявлений в цифрах в скобке.

Я думаю, что нам необходимо будет что-то поменять в нижеследующем коде (cat_index_inc.php) :
$sql = "
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count
// думаю, что нам нужно тут что-то изменить, чтобы код показал список только кореных
// категорий
FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category  where cat.id = cat.root_category
    "
.
        (
        defined('JBCITY')
        ? "WHERE AND b.city_id = " . JBCITY
        : ""
    ) . "
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.$title_key ASC
    "
;


Если нам удастся вывести на главной странице только список коренных категорий с общим количеством объявлений в цифрах со скобками, то думаю, что проблема будет решена.
Спасибо всем, кто помогает мне. Особую благодарность хочу выразить 1234ru.
14.03.2012, 17:21
Ответить

1234ru

sogdianacha
нужно сделать так чтобы на главной отображались только коренные категории с общим кол-твом объявлений в цифрах в скобке.


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

# 2. Перестраиваем массив данных меню
#    в соответствии с его иерархической структурой

$T = new Tree_Builder;
$menutree_all = $T->make_tree($menudata, 'count');

# 2.1. Фильтруем массив с меню,
#      оставляя только элементы с заданным parent_id

$parent_id = 0; // например, только корневые категории:
                // у них parent_id = 0
$menutree = array();
foreach ($menutree_all as $id => $row) {
    if ($row['parent_id'] == $parent_id)
        $menutree[$id] = $row;
}



Если так сделаете - будет именно то, что Вам требуется, я проверил.
То, что не убивает нас, делает нас инвалидами.
14.03.2012, 23:24
Ответить
NO USERPIC

sogdianacha

Здравствуйте,
Не могли бы подсказать как сделать так чтобы на главной отображались коренные категории. Спасибо.
05.03.2012, 04:21
Ответить
NO USERPIC

sogdianacha

Сейчас попробую протестировать. Сразу напишу результат.
15.03.2012, 03:25
Ответить
NO USERPIC

sogdianacha

Ура! Получилось, наконец!
Михаил, огромное Вам спасибо. Желаемый результат наконец достигнут. Все как я хотела. Я еще раз убедилась в том, что на свете есть хорошие и добрые люди как Вы. Если чем смогу помочь Вам, то буду очень рада этому. Спасибо Вам большое.
С уважением, Согдиана
15.03.2012, 04:46
Ответить

1234ru

Пожалуйста, Согдиана :)

Хорошо, что все получилось.
То, что не убивает нас, делает нас инвалидами.
15.03.2012, 06:15
Ответить
NO USERPIC

sogdianacha

Здравствуйте Михаил. Как Вы? У меня одна проблема. Во время работы со скриптом. Когда я перехожу по генерированным ссылкам cat_index.php, иногда система выдает такую ошибку. Очень нужна Ваша помощь. Ошибку приведу ниже. Я сама не смогла разобраться. Вот сообщение об ошибке:
MySQL error in file /тут путь до cat_index.inc.php /cat_index.inc.php at line 40 (function mysql_gettable):
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AND b.city_id = 251 GROUP BY cat.id ORDER BY cat.sort_index DESC, cat.' at line 12
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count
    FROM jb_board_cat AS cat
    LEFT JOIN jb_board AS b ON cat.id = b.id_category
    WHERE AND b.city_id = 251
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.name_cat ASC
   

Пожалуйста, помогите. Спасибо.
03.04.2012, 01:07
Ответить

1234ru

Здравствуйте, Согдиана.
Спасибо, вроде ничего :)

Это еще в одном из предыдущих сообщений я немного ошибся - вот тут лишний AND:
? "WHERE AND b.city_id = " . JBCITY

Вот так должен выглядеть запрос (сообщение выше тоже исправил):

$sql = "
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count
// думаю, что нам нужно тут что-то изменить, чтобы код показал список только кореных
// категорий
FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category  where cat.id = cat.root_category
    "
.
        (
        defined('JBCITY')
        ? "WHERE b.city_id = " . JBCITY
        : ""
    ) . "
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.$title_key ASC
    "
;


P.S. Ошибки закрадываются, т.к. пишу вслепую, без тестирования кода.
То, что не убивает нас, делает нас инвалидами.
03.04.2012, 01:16
Ответить
NO USERPIC

sogdianacha

Спасибо, что так быстро ответили. Мне нужно скопировать в файл cat_index.inc.php код который указан на этом последнем сообщении?:
http://webew.ru/posts/2823.webew#4314. Спасибо.
03.04.2012, 01:43
Ответить

1234ru

Ну да. Здесь просто SQL-запрос немного исправлен - его и замените (Вы его привели в своем предыдущем сообщении).
То, что не убивает нас, делает нас инвалидами.
03.04.2012, 02:43
Ответить
NO USERPIC

sogdianacha

Спасибо. Иду заменять. О результатах напишу скоро.
03.04.2012, 02:48
Ответить
NO USERPIC

sogdianacha

Теперь, система выдает такое сообщение:
MySQL error in file /тут путь до/cat_index.inc.php at line 40 (function mysql_gettable):
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE b.city_id = 462 GROUP BY cat.id ORDER BY cat.sort_index DESC, cat.' at line 11
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category  where cat.id = cat.root_category
    WHERE b.city_id = 462
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.en_name_cat ASC

Как быть? Я скопировала этот код
$sql = "
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count FROM jb_board_cat AS cat
LEFT JOIN jb_board AS b ON cat.id = b.id_category  where cat.id = cat.root_category
    "
.
        (
        defined('JBCITY')
        ? "WHERE b.city_id = " . JBCITY
        : ""
    ) . "
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.$title_key ASC
    "
;
и заменила его с прежним кодом.
03.04.2012, 03:02
Ответить

1234ru

Так.. Не до конца я исправил.
Возьмите вот такой код:

$sql = "
    SELECT
        cat.id AS id,
        cat.root_category AS parent_id,
        cat.name_cat,
        cat.sort_index,
        cat.en_name_cat,
        cat.description,
        cat.img,
        SUM(IF(b.old_mess = 'old', 1, 0)) AS count FROM jb_board_cat AS cat
    LEFT JOIN jb_board AS b ON cat.id = b.id_category  
    WHERE cat.id = cat.root_category
    "
. (defined('JBCITY') ? " AND b.city_id = " . JBCITY : "") . "
    GROUP BY cat.id
    ORDER BY cat.sort_index DESC, cat.$title_key ASC
    "
;


(не заметил, что WHERE идет в строке вместе с JOIN).
То, что не убивает нас, делает нас инвалидами.
04.04.2012, 22:22
Ответить
Добавить комментарий
Отображение комментариев: Древовидное | Плоское
© 2008—2024 webew.ru, связаться: x собака webew.ru
Сайт использует Flede и соответствует стандартам WAI-WCAG 1.0 на уровне A.
Rambler's Top100

Реклама: