这是一个时间序列问题。在这个lockactivity表中你有一系列击键(与其他东西混合)。我们需要将击键分成彼此相邻的组。
此查询(http://sqlfiddle.com/#!2/6ffed/21/0)这样做。为了完整起见,我要离开*
击键。
SELECT TIMESTAMPDIFF(SECOND, @prevVal, req_time) AS timediff,
@prevVal := req_time AS req_time,
lockip, keyvalue
FROM lockactivity,
(SELECT @prevVal := MIN(req_time) -
INTERVAL 1 HOUR FROM lockactivity) AS r
WHERE LENGTH(keyvalue) = 1
ORDER BY lockip, id
结果集的前几行是这样的:
TIMEDIFF REQ_TIME LOCKIP KEYVALUE
3604 2014-02-27 09:29:55 192.168.1.49 3
0 2014-02-27 09:29:55 192.168.1.49 6
1 2014-02-27 09:29:56 192.168.1.49 4
0 2014-02-27 09:29:56 192.168.1.49 1
0 2014-02-27 09:29:56 192.168.1.49 *
1155 2014-02-27 09:49:11 192.168.1.49 3
见按键的每一个新的“一堆”如何与一个比较大的timeDiff测量开始?
我们的下一步是创建一个计划,在每串按键上添加一个新的序列号。这个讨厌的查询(http://sqlfiddle.com/#!2/6ffed/25/0)这样做。
SELECT TIMESTAMPDIFF(SECOND, @prevVal, req_time) AS timediff,
IF(ABS(TIMESTAMPDIFF(SECOND, @prevVal, req_time))> 120,
@seq:[email protected]+1,
@seq) AS seq,
@prevVal := req_time AS req_time,
lockip, keyvalue
FROM lockactivity,
(SELECT @prevVal := MIN(req_time) -
INTERVAL 1 HOUR FROM lockactivity) AS r,
(SELECT @seq := 0) AS s
WHERE LENGTH(keyvalue) = 1
ORDER BY lockip, id
注意上面的120
。我任意选择将具有120秒或更少的延迟的击键群集起来。您可能需要选择不同的群集编号。还要注意,当我们获得第二个ip时,timediff向后跳,所以我使用ABS()
作为聚类准则。
最后,我们需要用GROUP_CONCAT等来总结这个东西。这个查询(http://sqlfiddle.com/#!2/6ffed/28/0)这样做。
SELECT lockip,
GROUP_CONCAT(keyvalue
ORDER BY id
SEPARATOR '') AS keystrokes,
MAX(req_time) AS finish_time
FROM (
SELECT TIMESTAMPDIFF(SECOND, @prevVal, req_time) AS timediff,
IF(ABS(TIMESTAMPDIFF(SECOND, @prevVal, req_time))> 120,
@seq:[email protected]+1,
@seq) AS seq,
@prevVal := req_time AS req_time,
id, lockip, keyvalue
FROM lockactivity,
(SELECT @prevVal := MIN(req_time) -
INTERVAL 1 HOUR FROM lockactivity) AS r,
(SELECT @seq := 0) AS s
WHERE LENGTH(keyvalue) = 1
ORDER BY lockip, id
) AS seq
GROUP BY seq, lockip
ORDER BY MAX(req_time)
下面是结果集,它看起来正是你所需要的。我不完全确定最后两个关键序列。您可能需要摆弄集群时间才能正确使用这些东西。
LOCKIP KEYSTROKES FINISH_TIME
192.168.1.49 3641* 2014-02-27 09:29:56
192.168.1.49 3 2014-02-27 09:49:11
192.168.1.49 3641* 2014-02-27 20:29:49
192.168.1.49 3641* 2014-02-27 20:33:32
192.168.1.55 1122* 2014-02-27 21:06:42
192.168.1.55 1122** 2014-02-27 21:45:52
192.168.1.55 1122* 2014-02-27 22:12:38
192.168.1.49 3641*11015* 2014-02-27 22:13:11
192.168.1.49 33015*11015* 2014-02-27 22:20:10
最后,OP对查询进行了一些进一步调整,以拆分星号分隔的序列。
jinxjy更新:根据我的评论,我对上面的最后一个查询做了一些小的修改,除了之前创建的时间戳序列之外,还使用*作为分隔符。其他小编辑包括将120更改为6,因为这是键盘上的标准按键超时,并将*隐藏在最终代码列中。这也被发布到sqlfiddle(http://sqlfiddle.com/#!2/6ffed/53/0)
SELECT lockip,
GROUP_CONCAT(keyvalue
ORDER BY id
SEPARATOR '') AS code,
MAX(req_time) AS finish_time
FROM (
SELECT TIMESTAMPDIFF(SECOND, @prevVal, req_time) AS timediff,
IF(keyvalue="*",
@flag:=1,
@flag:=0) AS flag,
IF(ABS(TIMESTAMPDIFF(SECOND, @prevVal, req_time))> 6,
@seq:[email protected][email protected],
@seq:[email protected][email protected]) AS seq,
@prevVal := req_time AS req_time,
id, lockip, keyvalue
FROM lockactivity,
(SELECT @prevVal := MIN(req_time) - INTERVAL 1 HOUR FROM lockactivity) AS r,
(SELECT @seq := 0) AS s,
(SELECT @flag:= 0) AS n
WHERE LENGTH(keyvalue) = 1
ORDER BY lockip, id
) AS seq
WHERE flag=0
GROUP BY seq, lockip
ORDER BY MAX(req_time) DESC
这给了我理想的结果:
| LOCKIP | CODE | FINISH_TIME |
|--------------|-------|---------------------|
| 192.168.1.49 | 11015 | 2014-02-27 22:20:10 |
| 192.168.1.49 | 33015 | 2014-02-27 22:20:04 |
| 192.168.1.49 | 11015 | 2014-02-27 22:13:11 |
| 192.168.1.49 | 3641 | 2014-02-27 22:13:06 |
| 192.168.1.55 | 1122 | 2014-02-27 22:12:38 |
| 192.168.1.55 | 1122 | 2014-02-27 21:45:48 |
| 192.168.1.55 | 1122 | 2014-02-27 21:06:41 |
| 192.168.1.49 | 3641 | 2014-02-27 20:33:32 |
| 192.168.1.49 | 3641 | 2014-02-27 20:29:48 |
| 192.168.1.49 | 3 | 2014-02-27 09:49:11 |
| 192.168.1.49 | 3641 | 2014-02-27 09:29:56 |
有趣的问题!
尽管有办法从表格中获取安全代码,但我认为当表格变大时它们会很贵。我不禁想到合并键击应该由代码从键盘获取事件并将其存储到数据库中,而不是存储每个原始键击。 – Barmar
欢迎来到SO。感谢仔细思考的问题。它看起来像有一个按键的时间序列,而且不同的代码以大于几秒的时间分隔。 –
@Barmar:这几乎花了我几个月的时间才能得到原始的按键!这些按键发送的小键盘的自动化能力非常有限,所以我的选择是通过数据库处理这些数据,或者构建一个Web服务,在通往数据库的途中陷入并构建代码。如果目前的方法长期存在任何问题,我将调查Web服务的可能性。感谢您的回应。 – jinxjy