有时我想用我们拥有的一些访问日志来做这样的事情。我的数据如下:
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 | ...
然后我想通过用户 ID 识别一个“会话”以及时间是否“块”,这就是我阅读您的陈述的方式。所以,从上面来看:
UserId | SessionStart | Stuff
--------|--------------------|---------
33 | 6/14/2009 14:05:17 | ...
33 | 6/14/2009 14:27:19 | ...
我使用 SQL Server 在 SQL 中执行此操作。在这种情况下,我的策略是:
- 按用户分组
- 确定每行两条记录之间的差异。
- 如果增量超过我的阈值,则创建一个 IsNewSession 列,否则为 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
;