Иногда я хочу сделать что-то подобное с некоторыми журналами доступа, которые мы имеем. Мои данные выглядят так:
EventID | UserID | When | What
--------|--------|---------------------|--------
7477 | 33 | 20090614:140517.131 | ...
7478 | 33 | 20090614:140518.992 | ...
7479 | 33 | 20090614:140522.020 | ...
7480 | 33 | 20090614:142719.001 | ...
7481 | 33 | 20090614:142720.668 | ...
Тогда я хочу идентифицировать «сессию» по идентификатору пользователя, и не будет ли время «комом», именно так я читаю ваше утверждение. Итак, из вышесказанного:
UserId | SessionStart | Stuff
--------|--------------------|---------
33 | 6/14/2009 14:05:17 | ...
33 | 6/14/2009 14:27:19 | ...
Я делаю это в SQL, используя SQL Server. Моя стратегия в этом случае:
- Группировка по пользователю
- Определение дельты между двумя записями в строке.
- Создайте столбец IsNewSession со значением 1, если дельта превышает мой порог, иначе 0. Эта запись является временем / датой нового сеанса.
- Создайте столбец SessionNumber, который является промежуточной суммой IsNewSession. Затем вы можете использовать этот номер для идентификации записей в сеансе, группировки по ним и т. Д.
В SQL Server, используя временную таблицу, это довольно быстро. Используя один оператор SQL, он быстро становится очень медленным. В обоих случаях это действительно безобразно. Oracle, с другой стороны, имеет хороший набор аналитических функций для обработки дельты и промежуточного итога, что делает код более чистым и (обычно) более быстрым.
Если у mysql нет такой магии, и если ваша команда не особенно увлечена SQL, я бы порекомендовал вам просто рассмотреть возможность сделать это в своем приложении для поддерживаемого производственного кода.
Ниже приведена дезинфицированная версия того, что я использую. Если вам нужна версия «одного оператора SQL», дайте мне знать. Извиняюсь за то, что предоставил вам код SQL Server вместо mysql. :)
-- Set up work table
DROP TABLE #temp
CREATE TABLE #temp
(
ID INT PRIMARY KEY,
EventDate DATETIME,
RecordRank INT,
IsNewSession INT,
SessionNum INT
);
DECLARE
@NumSecondsBetweenSessions INT,
@StartDate DATETIME,
@EndDate DATETIME
;
SELECT
@NumSecondsBetweenSessions = 600,
@StartDate = '20000101',
@EndDate = '20201231'
;
-- Set up what will be our "Current" records in the "Current vs
-- Previous" comparision.
INSERT INTO #temp
(
ID,
EventDate,
RecordRank,
IsNewSession,
SessionNum
)
SELECT
SL.ID,
SL.Created_DateTime,
ROW_NUMBER() OVER (ORDER BY SL.Created_DateTime ASC) AS RecordRank,
0,
0
FROM
SystemLog SL
WHERE
SL.Created_DateTime BETWEEN @StartDate and @EndDate
;
-- Checking the time delta between the Current and Previous
-- records to see if we have a new session.
UPDATE #temp
SET
IsNewSession =
CASE
WHEN PrevT.EventDate IS NULL THEN 1
WHEN DATEDIFF(s, PrevT.EventDate, #temp.EventDate) > @NumSecondsBetweenSessions THEN 1
ELSE 0
END
FROM
#temp
LEFT OUTER JOIN #temp PrevT
ON #temp.RecordRank = (PrevT.RecordRank + 1)
;
-- This is performing a "running total" on IsNewSession to assign
-- records to a specific Session.
DECLARE @SessionNum INT;
SET @SessionNum = 0;
UPDATE #temp
SET
@SessionNum = @SessionNum + IsNewSession,
SessionNum = @SessionNum
;
-- The results.
SELECT
T.*,
SL.*
FROM
#temp T
JOIN SystemLog SL
ON SL.ID = T.ID
ORDER BY
RecordRank ASC
;