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

Форум MySQL

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

 

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

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

тема: Нужно упростить SQL запрос.
 
 автор: Dr Lines   (09.12.2008 в 08:01)   письмо автору
 
 

Итак, есть статистика посещяемости сайта, выводимая из базы SQL.

Вывод происходит из двух таблиц синхронно.

Вывод статистики выглядит так:


1    172.25.18.24    %unkmow%       7
2    172.25.18.23    MaJIbILLI            392
3    172.25.18.18    %unkmow%      125
4    172.25.18.16    MAD              801
5    172.25.18.12    %unkmow%      1
6    172.25.112.60    %unkmow%      1


Первая колонка - порядковый номер (значение не имеет, т.к. берется не из базы sql)
Вторая колонка - IP пользователя
Третяя колонка - Имя пользователя (Выполняется проверка в другой таблице, на совпадение с IP из второй колонки, если оно есть, то выводится соответствующее имя)
Четвертая колонка - Количество посещений.

Итак, в первой таблице хранятся данные о посещениях.
Из этих данных требуется только IP посетителя.
И сколько раз этот IP встречается в этой таблице (т.е сколько раз этот пользователь посещал данную страницу.)

Во второй таблице хранится информация об именах пользователей.
В ней записан IP и имя пользователя с этим IP.
===========================================================
Так работает мой вариант статистики:

1. Выполняется запрос на получение всех уникальных IP адресов из первой таблицы.
$get_ip_list=mysql_query("SELECT DISTINCT `ip` FROM `post` ORDER BY `ip` DESC;")


2. Теперь, поcредством PHP функции mysql_fetch_array() выполняется пробег по всем полученным IP адресам
$ire=0;
while($ip_list_array=mysql_fetch_array($get_ip_list))
{
 $ire++;
 #дальнейшие интрукции
}


3. Итак, получив IP адрес, нужно для каждого определить сколько раз он встречается в первой таблице и получить имя пользователя с этим IP из второй таблицы. Это и есть " #дальнейшие интрукции"


//Получаем количество посещений для IP:
$visitings=mysql_num_rows(mysql_query("SELECT `number` FROM `post` WHERE `ip` LIKE '".$ip_list_array[0]."';"));
//Попытка получить имя для IP из второй таблицы:
$user_name_a=mysql_fetch_array(mysql_query("SELECT `name` FROM `users` WHERE `ip` LIKE '".$ip_list_array[0]."';"));
//Дальше, выполняется проверка существует ли совпадение с IP во второй таблице.
//Если совпадения нет то выведется %unkmow%, если есть, то выведется то, что было найдено во
//второй таблице.
 if(isset($user_name_a[0])){$user_name=$user_name_a[0];}else{$user_name="%unkmow%";}
 echo "<tr><td>$ire</td><td>$ip_list_array[0]</td><td>$user_name</td><td>$visitings</td></tr>\n";



Так работает мой вариант.
Но он очень громозкий. Его надо упростить, потому что выполняется очень медленно.
========================================================================
Итак, я жду ваших предложений по упрощению конструкции этого кода.


Заранее благодарен.

  Ответить  
 
 автор: Trianon   (09.12.2008 в 10:28)   письмо автору
 
   для: Dr Lines   (09.12.2008 в 08:01)
 

1. Для сравнения значений LIKE не применяют.
2. Чтобы получить число строк в таблице, запрашивают именно число строк, а не сами строки.
3. оба запроса можно было бы переписать в один, если ip для второй таблицы - уникальный ключ.

SELECT post.ip AS pip, MAX(users.name) as nm, COUNT(*) AS cnt 
FROM post JOIN users ON post.ip = users.ip
GROUP BY pip 

  Ответить  
 
 автор: Valick   (09.12.2008 в 10:45)   письмо автору
 
   для: Trianon   (09.12.2008 в 10:28)
 

если ip для второй таблицы - уникальный ключ
Как прикажете понимать?)) Мне казалось по поводу ip у вас пунктик))

  Ответить  
 
 автор: Trianon   (09.12.2008 в 10:59)   письмо автору
 
   для: Valick   (09.12.2008 в 10:45)
 

А что непонятно?
Если в таблице users поле ip уникальным не является, то name в запросе оказывается неоднозначным уже не формально (для чего я собственно и написал MAX()), а фактически.

По поводу пунктика, если можно, раскажите поподробнее.

  Ответить  
 
 автор: Valick   (09.12.2008 в 11:17)   письмо автору
 
   для: Trianon   (09.12.2008 в 10:59)
 

По поводу уникального поля и самого запроса всё понятно.
По поводу пунктика, позвольте процитировать

 автор: Trianon   (27.08.2007 в 22:00)   письмо автору   
   для: kasmanaft   (27.08.2007 в 20:07)  
  не трогайте IP. Оно не Ваше.

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

  Ответить  
 
 автор: Trianon   (09.12.2008 в 11:29)   письмо автору
 
   для: Valick   (09.12.2008 в 11:17)
 

Конечно, мне это не нравится.
Но, по-моему, вопросов проектирования автор не ставил.
Поэтому я решил в бутылку не лезть.

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 12:07)   письмо автору
 
   для: Valick   (09.12.2008 в 11:17)
 

Этот код расчитан на работу в локальной сети, в которй у всех уникальные IP адреса.

  Ответить  
 
 автор: Trianon   (09.12.2008 в 12:18)   письмо автору
 
   для: Dr Lines   (09.12.2008 в 12:07)
 

у кого у всех? )))

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 12:51)   письмо автору
 
   для: Trianon   (09.12.2008 в 12:18)
 

Я сказал локальной сети, а не интернета.
А подменить IP на чужой в ней не получится (даже если сменить mac-адрес), уж так она устроена.
Вобщем это не касается данного вопроса. Так что забудем.

Да, кстати ваш код выдает ошибку здесь:
MAX(users.name)
#1054 - Unknown column 'users.name' in 'field list'
хотя таблица users существует и столбец с заголовком name у неё тоже присутствует.

  Ответить  
 
 автор: Trianon   (09.12.2008 в 13:07)   письмо автору
 
   для: Dr Lines   (09.12.2008 в 12:51)
 

проверяйте. У меня этот запрос выполняется нормально.

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 13:28)   письмо автору
 
   для: Trianon   (09.12.2008 в 13:07)
 

Вобщем поковырялся и сделал рабочий вариант:

SELECT `users`.`ip` AS `ip`, `users`.`name` AS `name`, 
COUNT(*) AS `count` 
FROM `post` JOIN `users` 
WHERE `post`.`ip`  ='172.16.70.11' 
AND `post`.`ip` = `users`.`ip` 
GROUP BY `users`.`name` ASC ;

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 13:47)   письмо автору
 
   для: Trianon   (09.12.2008 в 13:07)
 

Мде, упростить - упростили, а на скорость выполнения это никак не повлияло. (больше 90 секунд выполняет при таблице с 80ю тысячами записями.)

Видимо надо свеси всё до 1го запроса. Тобишь и DISTINCT(`ip`) и все остальное. Буду ломать голову дальше.....

  Ответить  
 
 автор: Trianon   (09.12.2008 в 14:53)   письмо автору
 
   для: Dr Lines   (09.12.2008 в 13:47)
 

последний запрос делает совершенно не то, что мой.
Впрочем дело Ваше.

индексы на полях ip с и name cтоят?

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 15:23)   письмо автору
 
   для: Trianon   (09.12.2008 в 14:53)
 

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

Что на счет вашего запроса, то получается он выводит только те IP адреса, для которых были найдены имена из второй таблицы. А остальные IP он не выводит.
Надо чтобы запрос вывел все результаты, а у кого найдет имя - и имя вывел тоже.

  Ответить  
 
 автор: Trianon   (09.12.2008 в 15:29)   письмо автору
 
   для: Dr Lines   (09.12.2008 в 15:23)
 

>Да, у каждой из таблиц есть поле индекс с авто инерементом (`number`), я его тут не описывал.

Вы запрашиваете отбор строк по полю ip . И (непонятно зачем) группировку по name. При чем тут number?



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

LEFT JOIN

  Ответить  
 
 автор: Dr Lines   (09.12.2008 в 16:10)   письмо автору
 
   для: Trianon   (09.12.2008 в 15:29)
 

Все, проблема решена.

Использовал:

SELECT `post`.`ip` AS `ip`, 
MAX(`users`.`name`) AS `name`, 
COUNT(*) AS `count` FROM `post` LEFT JOIN `users` 
ON `post`.`ip` = `users`.`ip` GROUP BY `ip`;


Таблицу из 86497 записей прощитал за 4 секунды.!

Trianon, благодарю за предоставленное решение.

  Ответить  
Rambler's Top100
вверх

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