Глупый вопрос человека сломавшего моск

kode

never knows best
Глупый вопрос человека сломавшего моск

Дано:

Таблица-лог, аля:

id, time, nick, action (enum: login, logout)

Сразу скажу что это не относится к вебу никаким образом.

Мне нужно получить среднее время входа и выхода в часах человека, при условии что разница между ними может быть более 24 часов, а может и составлять 5 минут. Те например Человек обычно появляется с 10 часов до 18.
 

rotoZOOM

ACM maniac
"разница между ними" это между кем/чем (людьми, входами одного человека, входами-выходами одного человека) ?
Если человек входил три раза в 00:00, затем в 08:00 и затем в 16:00, то какое будет среднее время входа ?
 

kode

never knows best
входами-выходами....

в том-то и дело :) Если использовать стандартную avg аля sum / count это будет неверно.

Тут надо "другое" решение....
 

Pigmeich

Новичок
kode
Вот сразу видно, что тебе нифига не видно.

0. Лог - это ведь записи отсортированные по времени в порядке возрастания? Если нет - отсортируй.

1. Далее, заводим массив на всех пользователей (либо динамически будем добавлять новых встретившихся).

2. Едем по логу:
2.1. Если на встретившивося логинящегося человека нет карточки в массиве - записываем в массив данные по времени
2.2. Если уже записан но логается
2.2.1. Записи нелегальны (после лога должен быть логаут)
2.2.2. Прикидываем просроченный срок. И выходим на 2 уровень.
2.3. Если логаут
2.3.1. Нет записей?
2.3.2. Прикидываем срок. И выходим на 2 уровень
2.3.2. Просрочен ли срок?
2.3.2.1. Считаем просроченный. И выходим на 2 уровень.
2.3.3 С чистой совестью записываем разницу.


С тебя бутылочка "Швепса", если я тебя вдруг встречу.
 

kode

never knows best
Автор оригинала: Pigmeich
kode
Вот сразу видно, что тебе нифига не видно.

0. Лог - это ведь записи отсортированные по времени в порядке возрастания? Если нет - отсортируй.

1. Далее, заводим массив на всех пользователей (либо динамически будем добавлять новых встретившихся).

2. Едем по логу:
2.1. Если на встретившивося логинящегося человека нет карточки в массиве - записываем в массив данные по времени
2.2. Если уже записан но логается
2.2.1. Записи нелегальны (после лога должен быть логаут)
2.2.2. Прикидываем просроченный срок. И выходим на 2 уровень.
2.3. Если логаут
2.3.1. Нет записей?
2.3.2. Прикидываем срок. И выходим на 2 уровень
2.3.2. Просрочен ли срок?
2.3.2.1. Считаем просроченный. И выходим на 2 уровень.
2.3.3 С чистой совестью записываем разницу.


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

FractalizeR

Новичок
Этот лог - база данных? SQL нужно использовать или что? Гарантируется, что каждому логин соответствует logout?
 

kode

never knows best
Автор оригинала: FractalizeR
Этот лог - база данных? SQL нужно использовать или что? Гарантируется, что каждому логин соответствует logout?
Да, лог - БД. Не гарантируется...
 

Pigmeich

Новичок
kode
складываешь все периоды времени и делишь на рабочии дни.
 

WP

^_^
У тебя глупая структура, на этой структуре у тебя не хватит мозга, а у меня желания.
Сделай таблицу sessions с полями sid, userid, ctime, mtime.
По ней достаточно сделать
[SQL]
SELECT `userid`, AVG(`mtime`-`ctime`) FROM `sessions` WHERE userid=123
[/SQL]
 

kode

never knows best
WP
БД разработана не мной, и пишется из пропитиетарного софта....
 

Pigmeich

Новичок
kode
сделай view со структурой как у WP и вяжи зверский заджойненым запросом.

Или задампь в CVS, либо выбери все таблицу и делай как я написал.
 

BRat

o_0
kode
я имел ввиду твое несколько странное произношение этого слова -)
 

Gas

может по одной?
Код:
+------+---------------------+------+--------+
| id   | time                | nick | action |
+------+---------------------+------+--------+
|    1 | 2008-01-02 10:11:23 | user | login  |
|    2 | 2008-01-02 11:11:23 | user | logout |
|    3 | 2008-01-02 12:11:23 | user | login  |
|    4 | 2008-01-03 11:11:23 | user | logout |
|    5 | 2008-01-04 11:11:23 | user | login  |
|    6 | 2008-01-04 12:11:23 | user | login  |
|    7 | 2008-01-04 15:11:23 | user | logout |
|    8 | 2008-01-10 16:10:23 | user | login  |
|    9 | 2008-01-10 18:10:23 | user | login  |
|   10 | 2008-01-10 20:10:23 | user | login  |
|   11 | 2008-01-10 23:10:23 | user | logout |
|   12 | 2008-01-11 23:10:23 | user | login  |
+------+---------------------+------+--------+
[sql]
select sum(t_end-t_begin) as sec_total, sum(if(t_end>t_begin,1,0)) as cnt from
(select '_' as to_group, UNIX_TIMESTAMP(time) as t_begin,
(select UNIX_TIMESTAMP(`time`) from `log` where nick='user' and id > t1.id order by id limit 1) as t_end
from `log` as t1
where action='login' and nick='user') as t2
group by t2.to_group;
[/sql]

Результат: 126000 sec и 7 периодов. После выборки разделить 126000 на 7 и будет среднее время (но можно поверх обернуть в ещё один select и в нём разделить).

Использовались такие допущения:
1. поле `time` - datetime
2. значения поля `action` - login и logout (только те, между которыми нужно считать время)
3. разница считается между login и первым следующим logout или login, если конечное значение login - оно не учитывается.


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

-~{}~ 21.01.08 17:13:

Имхо, правильный вариант учитывать вход-выход только между парами login-logout, для случая:
1. login
2. login
3. logout
данные первого login'а будут проигнорированы, так-как точной инфы об окончании сессии нет (можно его учитывать, а время logout'а ставить константой - 5 мин, например):
[sql]
SELECT SEC_TO_TIME(t_in/cnt), SEC_TO_TIME(t_out/cnt) FROM (
SELECT sum(if(t_out is null, 0, t_in)) as t_in, sum(t_out) as t_out, sum(if(t_out is not null,1,0)) as cnt
FROM (
SELECT '_' AS to_group, UNIX_TIMESTAMP(`time`)%86400 AS t_in,
(SELECT if (action='login', null, UNIX_TIMESTAMP( `time` )%86400)
FROM `log`
WHERE nick = 'user' and action in ('login','logout') AND id > t1.id
ORDER BY id
LIMIT 1
) AS t_out
FROM `log` AS t1
WHERE ACTION = 'login' AND nick = 'user'
ORDER BY id
) as t2
GROUP BY t2.to_group
) as t3;
[/sql]
 

kode

never knows best
Gas
Большоё спасибо, но

Результаты вашего варианта сходны с AVG :))

Например, пользователь Kode находится круглосуточно :) Иногда редко прерываясь....те быстро вышел вошёл, но результат:

14:23:39 15:11:01

Получается что нахожусь 50 минут :)
 

Gas

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

Код:
SELECT SEC_TO_TIME( t_in / cnt ) AS t_in, (t_out / cnt) AS t_on_site
FROM (
  SELECT sum(IF(t_out IS NULL , 0, t_in%86400)) AS t_in, sum(t_out-t_in) AS t_out, sum(IF(t_out IS NOT NULL, 1, 0)) AS cnt
  FROM (
    SELECT '_' AS to_group, UNIX_TIMESTAMP( `time` ) AS t_in, 
      (
      SELECT IF (ACTION = 'login', NULL , UNIX_TIMESTAMP( `time` ))
      FROM `log` 
      WHERE nick = 'user' AND 
      ACTION IN ('login', 'logout') AND id > t1.id
      ORDER BY id
      LIMIT 1 
      ) AS t_out
    FROM `log` AS t1
    WHERE ACTION = 'login' AND nick = 'user'
    ORDER BY id
  ) AS t2
  GROUP BY t2.to_group
) AS t3;
t_on_site - среднее время на сайте в секундах
 
Сверху