Запрос, чтобы получить часы пик от сессионного стола - PullRequest
1 голос
/ 07 марта 2012

У меня есть таблица, содержащая пользовательские сеансы, то есть период, когда пользователь вошел в мое приложение. У каждого сеанса есть отметка времени начала и окончания.

Могу ли я одним запросом определить для каждого часа в день, сколько пользователей было в сети в то время (то есть, сколько сеансов было startTime <= hour AND endTime > hour)? Я хотел бы показать средние значения за последние 2 месяца, но если это невозможно, я могу справиться с запросом, который выполняет 1 день, и вычислить средние значения в сценарии.

Пример результата:

Hour    Online
00:00   10
01:00   12
02:00   10
....
16:00   100
17:00   120
....

(час также может быть простым целым числом, не имеет большого значения)

База данных MySQL 5.

Ответы [ 2 ]

1 голос
/ 07 марта 2012

Я ждал, чтобы кто-нибудь еще вмешался, так как я не разбираюсь в mysql, и я считаю, что должно быть лучшее решение.

Основная проблема здесь - это способ построить таблицу часов в день. Отсутствие рекурсивной способности выбора в MySQL заставило меня создать таблицу с помощью объединения. Даты проще, если мы можем принять пропущенные дни, когда никто не вошел в эту дату. Если нет, то для продления дат можно использовать тот же трюк, что и с часами, например, на семь дней. Перекрестное соединение создаст таблицу дат, каждая из которых будет иметь все 24 часа дня. Теперь нам нужно посчитать сеансы, которые были активны в данный момент. Для этого нам нужно усечь startTime до часовых границ и поместить объединенное время перекрестного соединения в усеченные startTime и endTime (для которых не требуется усечение). Наши данные наконец здесь.

Чтобы получить среднее значение за последние два месяца, просто включите этот выбор в еще один час группировки и вычислите avg (Users). Если вам действительно нужен один запрос для возврата обоих наборов данных, вы можете объединить этот запрос со средним запросом, где средний запрос будет возвращать ноль для даты.

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

select days.date, 
hour,
count (s.startTime) Users
from
(
    (
        select 0 hour
        union
        select 1 hour
        union
        select 2 hour
        union
        select 3 hour
        union
        select 4 hour
        union
        select 5 hour
        union
        select 6 hour
        union
        select 7 hour
        union
        select 8 hour
        union
        select 9 hour
        union
        select 10 hour
        union
        select 11 hour
        union
        select 12 hour
        union
        select 13 hour
        union
        select 14 hour
        union
        select 15 hour
        union
        select 16 hour
        union
        select 17 hour
        union
        select 18 hour
        union
        select 19 hour
        union
        select 20 hour
        union
        select 21 hour
        union
        select 22 hour
        union
        select 23 hour
    ) hours
    cross join
    (
    --  We need date portion only
        select distinct date(startTime) date from s 
        union select distinct date(endTime) from s
    ) days
)
left join s
-- date+hour, hopefully
   on date_add(date, interval hour HOUR) 
   -- startTime is truncated to hour, hopefully
      between date_sub(s.startTime interval minutes(s.startTime) MINUTE) 
      and s.endTime
-- last two months
where days.date between date_sub (now() interval 2 MONTH) and now()
group by days.date, hour
order by 1, 2
0 голосов
/ 07 марта 2012

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

SELECT hour, AVG(dayHourCount) FROM 

(
SELECT hour, day, dayHour, COUNT(*) AS dayHourCount FROM
(
SELECT hour, day, day + INTERVAL hour HOUR AS dayHour FROM
    (
        select 0 AS hour
        union
        select 1 AS hour
        union
        select 2 AS hour
        union
        select 3 AS hour
        union
        select 4 AS hour
        union
        select 5 AS hour
        union
        select 6 AS hour
        union
        select 7 AS hour
        union
        select 8 AS hour
        union
        select 9 AS hour
        union
        select 10 AS hour
        union
        select 11 AS hour
        union
        select 12 AS hour
        union
        select 13 AS hour
        union
        select 14 AS hour
        union
        select 15 AS hour
        union
        select 16 AS hour
        union
        select 17 AS hour
        union
        select 18 AS hour
        union
        select 19 AS hour
        union
        select 20 AS hour
        union
        select 21 AS hour
        union
        select 22 AS hour
        union
        select 23 AS hour
    ) AS hours

INNER JOIN (SELECT DISTINCT DATE(start) AS day FROM PlayerSession ds WHERE ds.start > NOW() - INTERVAL 1 MONTH) AS days
) AS dayHours

LEFT JOIN PlayerSession s ON (s.start < dayHour AND s.lastActivity > dayHour)
LEFT JOIN Player p ON (s.player_id = p.id)

GROUP BY dayHour

) AS perDayHour

GROUP BY hour
...