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

Форум PHP

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

 

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

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

тема: Выбор из БД MySQL
 
 автор: Kirill   (03.09.2004 в 11:09)   письмо автору
 
 

Есть таблица ip адресов. Она состоит из столбцов
id_ip, ip, id_author, time
Необходимо выбрать последний IP адрес для каждого автора, и время когда он с него зашел. Помогите пожалуйста.
Пользуюсь следующим запросом

SELECT ip, max(time) as time, id_author FROM ips GROUP BY id_author ORDER BY time DESC;

И у меня частенько путаются последние IP адреса. Т.е адрес не соответствует времени.

   
 
 автор: arka   (03.09.2004 в 15:47)
 
   для: Kirill   (03.09.2004 в 11:09)
 

Может быть заменить на
SELECT MAX(ip) AS max_ip, MAX(time) AS max_time, id_auth FROM ips GROUP BY id_auth ORDER BY time DESC

   
 
 автор: glsv (Дизайнер)   (03.09.2004 в 16:47)   письмо автору
 
   для: arka   (03.09.2004 в 15:47)
 

Нет, так тоже не получится. Это даст неправильные результаты.

   
 
 автор: arka   (03.09.2004 в 15:49)
 
   для: Kirill   (03.09.2004 в 11:09)
 

только вместо id_auth - id_author

   
 
 автор: glsv (Дизайнер)   (03.09.2004 в 16:40)   письмо автору
 
   для: Kirill   (03.09.2004 в 11:09)
 

Мне кажется это не получится сделать одним запросом, учитывая, что вложенные подзапросы MySQL в 3 версии не поддерживает :(

А запрос, да, не работает. Потому что если Вы запрашиваете 3 поля ip, max(time) as time, id_author и одно из них с агрегатной функцией max, то группировка должна идти по 2 оставшимся полям: ip и id_author. А у Вас только по одному GROUP BY id_author.

Поэтому нужно решать эту задачу по другому. Возможно придется переделывать структуру таблицы. Какую задачу Вы хотите решить с помошью этого запроса? Может быть можно ее немного изменить?

   
 
 автор: Kirill   (03.09.2004 в 18:25)   письмо автору
 
   для: glsv (Дизайнер)   (03.09.2004 в 16:40)
 

Хочу вывести последний IP адрес каждого пользователя. И время в которое он вошел под ним.
Приму любые варианты решений ;)

   
 
 автор: cheops   (03.09.2004 в 23:22)   письмо автору
 
   для: Kirill   (03.09.2004 в 18:25)
 

Сначала воодушивился :))), но эту задачу на MySQL похоже в один запрос не решишь (без вложенных запросов здесь мало чего сделаешь), сначала следует выбрать вторичные ключи авторов и соответствующее им время последнего посещения
SELECT distinct(id_author) AS id_author, max(time) AS max_time FROM ips GROUP BY id_author

а затем выбирать соответствующие им IP-адерса:
SELECT * FROM ips WHERE id_author=id_author AND time=max_time

Или на PHP:
<?php
$first 
mysql_query("SELECT distinct(id_author) AS id_author, max(time) AS max_time FROM ips GROUP BY id_author");
if(
$first)
{
  while(
$res mysql_fetch_array($first))
  {
    
$query "SELECT * FROM ips 
            WHERE id_author="
.$res['id_author']." AND time=".$res['max_time'];
    
$final mysql_query($query);
    
$result mysql_fetch_array($final);
    echo 
$result['ip']." - ".$result['time']."<br>";
  }
}
?>


PS Хм... хотя мне кажется это всё можно решить и в один присест :))) объединениями...

   
 
 автор: glsv (Дизайнер)   (03.09.2004 в 23:32)   письмо автору
 
   для: cheops   (03.09.2004 в 23:22)
 

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

   
 
 автор: Kirill   (03.09.2004 в 23:33)   письмо автору
 
   для: cheops   (03.09.2004 в 23:22)
 

спасибо :)
Вот такая вот вышла головоломка. Тест на знание MySQL ;)

   
 
 автор: Kirill   (03.09.2004 в 23:58)   письмо автору
 
   для: cheops   (03.09.2004 в 23:22)
 

Все хорошо, но можно ли все результаты выводить не в этом цикле?
Собрать все это в таблицу MySQL
Я слышал легенду о неких "временных" таблицах ;)

   
 
 автор: cheops   (04.09.2004 в 00:25)   письмо автору
 
   для: Kirill   (03.09.2004 в 23:58)
 

Обычно (в нормальных СУБД) для этого используют вложенные запросы, когда результаты одного запроса передают другому запросу...
>Я слышал легенду о неких "временных" таблицах ;)
Есть такой зверь :), что самое приятное, при создании таблиц вложенные запросы в MySQL работают. В следующем примере я не совсем честно обращаюсь с базой данных, но это должно работать:
<?php
  $query 
"CREATE TEMPORARY TABLE ttt SELECT id_author, time, ip FROM ips ORDER BY id_author,time DESC";
  
$sel "SELECT id_author, time, ip FROM ttt GROUP BY id_author";
  
mysql_query($query);
  
$res mysql_query($sel);
  if(
$res)
  {
    while(
$result mysql_fetch_array($res))
    {
      echo 
$result["id_author"]." ".$result["time"]." ".$result["ip"]."<br>";
    }
  }
?>

По заврешению php-скрипта или вызова функции mysql_close() таблица ttt будет уничтожена.

   
 
 автор: glsv (Дизайнер)   (03.09.2004 в 23:27)   письмо автору
 
   для: Kirill   (03.09.2004 в 18:25)
 

То есть будет сводная таблица со всеми пользователями и их последними IP. Или для каждого в отдельности.
Ведь для одного пользователя сосчитать это легко. А для всех сразу... элегантно не получается.
А вот такой вариант: А может быть в базе сразу хранить только последний IP? При занесении IP посетителя в базу все оставшиеся удалять, а новый заносить. Вернее это будет один запрос - на обновление данных.

   
 
 автор: Kirill   (03.09.2004 в 23:36)   письмо автору
 
   для: glsv (Дизайнер)   (03.09.2004 в 23:27)
 

> А вот такой вариант: А может быть в базе сразу хранить только >последний IP? При занесении IP посетителя в базу все >оставшиеся удалять, а новый заносить. Вернее это будет один >запрос - на обновление данных.

Так сделать нельзя, т.к. должен быть список всех IP пользователя =).
Т.е. изначально таблица, где показаны последние IP адреса пользователей, а также имеется возможность перехода к другой таблице, содержащей все IP адреса пользователя.

   
 
 автор: Kirill   (06.09.2004 в 20:26)   письмо автору
 
   для: Kirill   (03.09.2004 в 11:09)
 

Еще 1 задачка ;)
Возможно ли, на базе вашего форума (используя ту базу, что он имеет) подсчитать минимальное, среднее, максимальное среднее время которое прошло до первого ответа в теме? Или надо какую-нибудь таблицу добавить?

   
 
 автор: cheops   (07.09.2004 в 11:09)   письмо автору
 
   для: Kirill   (06.09.2004 в 20:26)
 

Не очень понятно вот что: это для одной темы или для всех тем форума?

PS Примерчик бы конкретный здесь очень бы помог, а то мы сейчас каждый о своём будем думать :))) (3 темы в них по 6 сообщений, нужно получить то-то...)

   
 
 автор: Kirill   (07.09.2004 в 14:10)   письмо автору
 
   для: cheops   (07.09.2004 в 11:09)
 

Есть форум (для того чтобы говорить на 1ом языке и решать 1 задачу. берем за основу БД для форума описанную в книге) .. в нем есть темы, в темах есть посты.
Так вот... необходимо найти средний, максимальный, минимальный промежуток времени между 1ым и вторым постом(если второй пост оставлен темже человеком, что и первый, то см третий etc) для всего форма (всех тем). Своеобразная скорость реакции (ответа) на вопрос.

   
 
 автор: cheops   (07.09.2004 в 15:28)   письмо автору
 
   для: Kirill   (07.09.2004 в 14:10)
 

Постараюсь ближе к полуночи сегодня более обстоятельно ответить... Здесь придётся тоже использовать временную таблицу с временами ответов посетителя, а потом проводить объединение её саму с собой, разница столбцов этого объединения даст нужный массив, в котором можно искать максимальное, минимальное и среднее... Работать, как и любое объединение это будет долго.

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

   
 
 автор: Kirill   (07.09.2004 в 15:59)   письмо автору
 
   для: cheops   (07.09.2004 в 15:28)
 

имеется ввиду разница между первым сообщением 1го автора и первым ответом на него любого дургого.
Причем ответом мы считаем любое сообщение в теме от другого автора.
Т.е. допустим
1.30 - Петя: hi
1.45 - Саша: hello
1.55 - ...
нас интересует промежуток между 1.30 и 1.45 все остальное мы опускаем
И так в каждой теме. А статистика общая для всего форума. т.е. выясняем промежутки во всех темах и дальше находим минимальный, максимальный и средний.

   
 
 автор: cheops   (07.09.2004 в 16:45)   письмо автору
 
   для: Kirill   (07.09.2004 в 15:59)
 

А... Т.е. авторы разные... Всё равно в один запрос не получится :( И даже помоему не получится обойтись без рекурсивного спуска в PHP, так как MySQL не поддерживает внешних ключей (в версии 4). Нужно будет разворачивать каждую тему вычисляя время между предыдущим и последующим сообщением и помещать их в массив... Мда... вся эта конструкция будет долго работать :))) Если захотите это применить на практике, следует сразу вычислять временную разницу, при добавлении сообщения и помещать в базу данных, чтобы разнести нагрузку во времени...

   
 
 автор: Kirill   (07.09.2004 в 16:58)   письмо автору
 
   для: cheops   (07.09.2004 в 16:45)
 

Обидно, но чтож.. веб программирование немного отличается от привычного :)

   
 
 автор: cheops   (07.09.2004 в 17:30)   письмо автору
 
   для: Kirill   (07.09.2004 в 16:58)
 

Да, я тоже долго привыкал :))), что программой могут одновременно по 100 человек пользоваться, а сама программа выполняется чёрт знает где и совсем не так как на локальной машине :)))

   
 
 автор: XPraptor   (07.09.2004 в 18:23)   письмо автору
 
   для: cheops   (07.09.2004 в 17:30)
 

Я вот провернул такую схему у меня все работает:
$rez=mysql_query( "SELECT id_author, ip, MAX(time_last) AS [mx_tm] FROM ips GROUP BY id_author, ip");
$tmp_auth=0;
$auth=0;
while($row=mysql_assoc_fetch($rez)){
$auth=$row["id_author"];
$mx_tm=$row["mx_tm"];
$ip=$row["ip"];
if($auth!=$tmp_auth){print "Time=".$mx_tm."IP=".$ip;}
$tmp_auth=$auth;
}


Результат запроса возвращает все строки но они отсортированы по убыванию максимального времени, поэтому каждая первая строка с новым ид автора это и есть время последнего посещения. Enjoy :-)

   
 
 автор: cheops   (07.09.2004 в 18:52)   письмо автору
 
   для: XPraptor   (07.09.2004 в 18:23)
 

Здесь IP-адрес не соответствует MAX(time_last) - я тоже сначала так хотел... :) Т.е. время-то максимальное, а IP-адрес первый попавшийся...

PS К тому же в этой ветке вторая проблема, надо было бы пост повыше запостить....

   
 
 автор: XPraptor   (08.09.2004 в 11:38)   письмо автору
 
   для: cheops   (07.09.2004 в 18:52)
 

Не знаю почему у тебя IP первый попавшийся, у меня все в порядке с ним, он именно от этой строки с последним временем посещения, так как группировка именно по этим двум полям.

   
 
 автор: cheops   (08.09.2004 в 12:32)   письмо автору
 
   для: XPraptor   (08.09.2004 в 11:38)
 

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

   
 
 автор: XPraptor   (08.09.2004 в 14:03)   письмо автору
 
   для: cheops   (08.09.2004 в 12:32)
 


[в базе]
217.21.51.1        1    07.09.2004
168.255.23.23    1    08.09.2004
123.142.23.25    1    09.09.2004
122.122.122.1    1    10.09.2004
241.232.232.1    2    07.09.2004
217.11.11.2        2    08.09.2004
222.11.22.11    3    07.09.2004
147.252.232.11    3    08.09.2004
165.236.215.32    3    09.09.2004
123.12.241.2    3    10.09.2004
123.245.123.1    4    07.09.2004
253.23.123.12    4    08.09.2004

[в запросе]
122.122.122.1    1    10.09.2004
123.142.23.25    1    09.09.2004
168.255.23.23    1    08.09.2004
217.21.51.1        1    07.09.2004
217.11.11.2        2    08.09.2004
241.232.232.1    2    07.09.2004
123.12.241.2    3    10.09.2004
147.252.232.11    3    08.09.2004
165.236.215.32    3    09.09.2004
222.11.22.11    3    07.09.2004
253.23.123.12    4    08.09.2004
123.245.123.1    4    07.09.2004

   
 
 автор: cheops   (08.09.2004 в 22:32)   письмо автору
 
   для: XPraptor   (08.09.2004 в 14:03)
 

Хм... хотя я наверное понял почему так... у меня в силу причин сейчас MySQL 3.23 стоит - наверное он так на запрос реагирует :)))

   
 
 автор: glsv (Дизайнер)   (07.09.2004 в 20:22)   письмо автору
 
   для: Kirill   (06.09.2004 в 20:26)
 

К примеру вот так. Жаль одним запросом не получается :(


<?
 
// выбираем авторов тем, чтобы затем исключить их из следующего запроса
  
$query1="Select id_theme, id_author, author from posts where parent_post=0 group by id_theme";
  
$res mysql_query($query1);   
  if(
$res
  { 
    while(
$result mysql_fetch_array($res)) 
    { 
       
// запрашиваем темы, минимальное время ответа. Автор поста не должен быть равен автору темы.
       
$query2="Select id_theme, min(time) as min_time from posts where id_author<>".$result['id_author']." and id_theme=".$result['id_theme']." group by id_theme";
       
$resposts mysql_query($query2); 
       if(
$resposts
        { 
         while(
$result2 mysql_fetch_array($resposts)) 
         { 
             echo 
$result2["id_theme"]." | "
           echo 
$result2["min_time"]."<br>"
         } 
       } 
    } 
  } 
?>

   
Rambler's Top100
вверх

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