Как написать запрос MySQL для выборки счетчиков на основе временных диапазонов? - PullRequest
0 голосов
/ 05 марта 2012

У меня есть такой стол:

userId     loggedtime
-------------------
1        2012-03-05 10:45:59
2        2012-03-05 10:04:19
2        2012-03-05 10:05:09
4        2012-03-05 10:20:24
3        2012-03-05 10:20:20
6        2012-03-05 10:30:59
7        2012-03-05 10:35:59

Я хочу выбрать, сколько пользователей вошли в каждый 5-минутный интервал между 10 и 11 часами.

Мне нужен такой результат.

time       count
---------------
10:05        2 
10:20        2 
10:30        1 
10:35        1

Как мне написать запрос MySQL для создания такого рода результата?

Ответы [ 5 ]

3 голосов
/ 05 марта 2012

Вам просто нужно придумать что-то уникальное для группы, которое даст вам эти 5-минутные интервалы.

Если вы возьмете минуту времени и поделите ее на 5, то у вас появится нечто уникальное. Например, вы можете использовать GROUP BY CAST (EXTRACT (MINUTE FROM logTime) / 5 AS без знака), и это даст вам 5-минутные интервалы уникальности. По умолчанию / 5 будет делиться без округления.

Чтобы написать рабочий запрос, попробуйте выполнить его поэтапно.

Во-первых, давайте возьмем минуту:

mysql> SELECT userid, EXTRACT(MINUTE FROM loggedtime) as minute from test;
+--------+--------+
| userid | minute |
+--------+--------+
|      1 |     45 |
|      2 |      4 |
|      2 |      5 |
|      4 |     20 |
|      3 |     20 |
|      6 |     30 |
|      7 |     35 |
+--------+--------+
7 rows in set (0.00 sec)

Теперь давайте попробуем создать значение столбца, уникальное для каждого 5-минутного интервала, который вы можете сгруппировать. Это минута, деленная на 5 без округления (указанное выше значение / 5):

mysql> select userid, EXTRACT(MINUTE FROM loggedtime) AS minute, CAST(EXTRACT(MINUTE FROM loggedtime) / 5 AS unsigned) FROM test;


+--------+--------+-------------------------------------------------------+
| userid | minute | CAST(EXTRACT(MINUTE FROM loggedtime) / 5 AS unsigned) |
+--------+--------+-------------------------------------------------------+
|      1 |     45 |                                                     9 |
|      2 |      4 |                                                     1 |
|      2 |      5 |                                                     1 |
|      4 |     20 |                                                     4 |
|      3 |     20 |                                                     4 |
|      6 |     30 |                                                     6 |
|      7 |     35 |                                                     7 |
+--------+--------+-------------------------------------------------------+
7 rows in set (0.01 sec)

Наконец, мы группируемся по этому уникальному столбцу. Этот запрос использует MIN () и MAX () для отображения первой и последней отметки времени в этом интервале, но вы также можете рассчитать время отключения, если хотите, чтобы оно точно соответствовало вашему вопросу.

mysql> SELECT COUNT(*) AS user_count, MIN(loggedtime) AS first_time, 
MAX(loggedtime) AS last_time 
FROM test 
GROUP BY CAST(EXTRACT(MINUTE FROM loggedtime) / 5 AS unsigned) 
ORDER BY last_time;
+------------+---------------------+---------------------+
| user_count | first_time          | last_time           |
+------------+---------------------+---------------------+
|          2 | 2012-03-05 10:04:19 | 2012-03-05 10:05:09 |
|          2 | 2012-03-05 10:20:20 | 2012-03-05 10:20:24 |
|          1 | 2012-03-05 10:30:59 | 2012-03-05 10:30:59 |
|          1 | 2012-03-05 10:35:59 | 2012-03-05 10:35:59 |
|          1 | 2012-03-05 10:45:59 | 2012-03-05 10:45:59 |
+------------+---------------------+---------------------+
5 rows in set (0.00 sec)
2 голосов
/ 05 марта 2012

Если вы собираетесь проводить этот анализ регулярно, возможно, стоит создать таблицу для ваших временных интервалов. Судя по вашим образцам данных и требуемым результатам, я бы создал таблицу:

Time_Intervals
I_Start      I_End
10:01:00     10:05:59
10:06:00     10:10:59
10:11:00     10:15:59
...
10:56:00     11:00:59

И, действительно, он будет содержать 12 интервалов для каждого часа каждого дня (хотя переход на 23: 56: 00..00: 00: 59 будет представлять некоторые развлечения - это оставлено в качестве упражнения для читатель!).

Затем вы можете просто использовать эту таблицу для генерации группировок:

SELECT i.i_end, COUNT(*)
  FROM Time_Intervals AS i
  JOIN ThisKindOfATable AS t
    ON t.loggedtime BETWEEN i.i_start AND i.i_end
 WHERE t.loggedtime BETWEEN '2012-03-05 10:01:00' AND '2012-03-05 11:00:59'
 GROUP BY i.i_end
 ORDER BY i.i_end;

Я использовал МЕЖДУ ... И для объединения. Альтернативный дизайн будет использовать диапазоны 10:01:00 .. 10:06:00 и условие соединения t.loggedtime >= i.i_start AND t.loggedtime < i.i_end; это лучше обрабатывает доли секунды.

Возможно, вам придется внести некоторые изменения в loggedtime, чтобы преобразовать его из DATE + TIME в просто TIME для условия соединения (возможно, TIME (t.loggedtime)). Вы также можете настроить это для печати нулей для тех интервалов, когда пользователи не входят в систему, используя левое соединение вместо внутреннего соединения. Вы также можете решить уменьшить количество секунд, чтобы упростить операции. Вариации легиона.

Основной альтернативой этому является преобразование заданного времени (t.loggedtime значений) в число интервалов с помощью некоторого соответствующего вычисления. Это относится к коду, специфичному для СУБД - функции для манипулирования временем практически не стандартизированы в СУБД.

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

Если вы хотите, чтобы он показывал 5-минутный интервал, в который пользователь соответственно вошел в систему, просто разделите INTEGER на (минута / 5), а затем умножьте на 5. Пример: 10:03 округлите до 0, умножьте на 5 будет представлять 10:00. 10:05 будет округлено до 1 * 5 = 10: 05

select
      concat( '10:', LPAD( floor( minute( UL.loggedTime ) / 5 ) * 5, 2, '0' ) as MinuteRange,
      count(*) as LoginCount
   from
      UserLoginTable UL
   where
      UL.loggedTime between '2012-03-05 10:00:00' AND '2012-03-05 10:59:59' 
   group by 
      MinuteRange

Да, это жестко закодировано для примера, но вы также можете заменить так много элементов ... интервал от 5 минут до 10 или 15 (или других), даже отформатировав начальный '10: '(часовое представление) использовать:

LPAD (час (UL.LoggedTime), 2, '0')

так что, если бы вы использовали более длинный временной диапазон ... скажем, с 21:00:00 до 23:59:59 были бы показаны все часы в этом диапазоне.

Просто обратите внимание. Поскольку вы сравниваете со столбцом даты / времени, в любом запросе, в котором вы хотите использовать только часть «дата», обязательно укажите весь диапазон дней с 00:00:00 до 11:59:59, иначе вы можете пропустить некоторые ожидаемые данные. .

0 голосов
/ 05 марта 2012

Попробуйте этот запрос

SELECT
    loggedTime,  
    count(UserId)
FROM tableName
WHERE loggedTime BETWEEN '2010-11-16 10:00:00' AND '2010-11-16 11:00:00' 
GROUP BY 
round(UNIX_TIMESTAMP(timestamp) / 300), name
0 голосов
/ 05 марта 2012

Я не знаю, как вы можете сделать это прямо сейчас, я должен больше думать о вашем необходимом результате. Но вы должны использовать timediff функцию в Mysql

пример:

SELECT TIMEDIFF('2009-02-01 00:00:00', '2009-01-01 00:00:00');

Абсолютно вы должны использовать цикл for в своем запросе MySQL для вычисления необходимого результата каждые 5 минут.

Посмотри на это тоже.

...