MySQL, к сожалению, не имеет так называемых оконных функций (что делает большинство других основных РСУБД), поэтому нам нужно приманить один из наших собственных. На самом деле это не так сложно, но было бы неплохо иметь поддержку ...
В любом случае, я сказал, что нам нужно было приманить функцию LAG()
, но это действительно так, что мы можем сравнить с увеличением группирования счетчика, так что мы можем на самом деле вырезать шаг, Сорт:
SELECT sentAt,
@Session := IF(sentAt < @SessionBoundary, @Session, @Session + 1) AS session,
@SessionBoundary := ADDTIME(sentAt, '00:30:00') AS sessionBoundary
FROM Message
JOIN (SELECT @Session := 0) n
ORDER BY sentAt
SQL Fiddle Example
Критически, обратите внимание, что, как это хорошая практика, чтобы использовать эксклюзивны верхнюю границу "(<
) для положительные типы непрерывного диапазона (например, date/time/timestamps), это 30th минута, что на самом деле начинается ваша новая сессия. То есть, начальное сообщение в 13:00 означает, что следующий сеанс начинается в 13:30 (без дополнительных сообщений). У этого есть приятное свойство сделать все, что выстраивается красиво, и что мне не нужно беспокоиться о странном поведении с дробными секундами, которые я, возможно, не указал.
В любом случае, это возвращает результаты так:
sentAt session sessionBoundary
2014-01-01 00:00:01 1 2014-01-01 00:30:01
2014-01-01 00:32:01 2 2014-01-01 01:02:01
2014-01-01 00:35:01 2 2014-01-01 01:05:01
2014-01-01 01:00:01 2 2014-01-01 01:30:01
2014-01-01 02:00:01 3 2014-01-01 02:30:01
2014-01-01 02:20:01 3 2014-01-01 02:50:01
Теперь, так как все, что вам нужен был простой подсчет, сколько session
s были, вы можете обернуть его в качестве подзапроса:
SELECT MAX(session)
FROM (SELECT sentAt,
@Session := IF(sentAt < @SessionBoundary, @Session, @Session + 1) AS session,
@SessionBoundary := ADDTIME(sentAt, '00:30:00') AS sessionBoundary
FROM Message
JOIN (SELECT @Session := 0) n
ORDER BY sentAt) MessageSession
(Примечание:. по какой-то причине я не понимаю, используя первоначальную работу в качестве подзапроса является причиной скрипку, чтобы начать на 0 вместо 1, что и до Пожалуйста, проверьте это на вашем сервере,s вам может понадобиться инициализировать с помощью @Session = 1
вместо 0 или использовать что-то вроде COUNT(DISTINCT session)
).
... И все готово.
Хотя вы только перечисленные желая граф, как только вы сеанс группировки вы можете иметь все виды весело с вашими данными. Теперь тривиально получить MAX(sentAt)
/MIN(sentAt)
для каждой группы, количество сообщений в группе или что-то еще. Например, вы могли бы сказать, «найти все давно запущенные сеансы» через что-то вроде этого:
SELECT session,
MIN(sentAt) AS firstMessageAt, MAX(sentAt) AS lastMessageAt, COUNT(*) AS messages
FROM (SELECT sentAt,
@Session := IF(sentAt < @SessionBoundary, @Session, @Session + 1) AS session,
@SessionBoundary := ADDTIME(sentAt, '00:30:00') AS sessionBoundary
FROM Message
JOIN (SELECT @Session := 0) n
ORDER BY sentAt) MessageSession
GROUP BY session
HAVING ADDTIME(MIN(sentAt), '24:00:00') < MAX(sentAt)
(найти всю сессию, которая уже в течение не менее 24 часов)
30 минут с того времени? Начало каждого часа? Некоторое случайное сообщение? Что произойдет, если у вас есть сообщения каждые 5 минут в течение 3 часов? Вы считаете, что вперед вовремя (как вы выбираете стартовые точки) или назад от текущего (что может изменить ваши сеансы)? Это некоторая форма анализа пробелов, которую MySQL не очень хорошо подходит (большинство других СУБД имеют функции, которые дадут дополнительную поддержку для таких вещей). –
Я надеялся, что мой пример будет иметь смысл. Так что да, оно начиналось с сообщения и заканчивалось последним сообщением, которое попадает в диапазон 30 минут последнего сообщения. К сожалению, я не могу отойти от MySQL, я привязан к MySQL и PHP –
И сообщение каждые 5 минут в течение трех часов приведет к 3-часовому сеансу. –