我有一个发生事件的数据库表:
(timestamp, other data...)
我想通过“几乎同时”发生的事情对这些事件进行分组。也就是说,当按时间戳排序时,每个组中的所有事件都在该组中某个其他事件的X秒(例如,X = 3)内,并且与其他组中的所有事件相距超过X秒。
有没有办法在SQL中有效地执行此操作,或者我应该只是按时间戳排序,将数据拉入我的应用程序,并在那里执行此操作?
答案 0 :(得分:1)
您可以使用UNIX_TIMESTAMP
和DIV
来计算与“同时”发生的事件相同的值。
以下计算10秒间隔内的事件数量:
SELECT UNIX_TIMESTAMP(timestamp) DIV 10, COUNT(*)
FROM events
GROUP BY 1;
答案 1 :(得分:1)
有时我想用我们拥有的一些访问日志来做这样的事情。我的数据如下:
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确定一个“会话”以及时间是否“乱”,这就是我在阅读你的陈述的方式。所以,从上面来看:
UserId | SessionStart | Stuff
--------|--------------------|---------
33 | 6/14/2009 14:05:17 | ...
33 | 6/14/2009 14:27:19 | ...
我在SQL中使用SQL Server执行此操作。我在这种情况下的策略是:
在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
;