MySQL差异某些行对的时间戳,并忽略所有其他行

时间:2018-02-01 06:53:28

标签: mysql

我有一个mysql表,由一个破损的应用程序提供服务,有几百万行,有无意义的登录/注销。此应用程序目前无法修复,因此我尝试编写一个查询,以区分任何和所有时间戳(在未显示的日期范围内)之间的时间(以秒为单位),该时间戳匹配“agentlogin”之前的“agentlogout”行,同时忽略不符合该条件的所有其他行。

我一直在这个网站上搜索了好几个小时,虽然我找到了一些很好的查询示例,但它们只能处理表格(由编写良好的应用程序提供服务),这些表格具有登录,然后是注销,而不是这些重复的东西。

这是表格:

+---------+---------------------+-------+-------------+------------------+
| id      | calldate            | agent | etype       | uniqueid         |
+---------+---------------------+-------+-------------+------------------+
| 1838073 | 2017-11-02 13:21:00 | 503   | agentlogoff | 1509628860.54414 |
| 1838232 | 2017-11-02 14:46:19 | 503   | agentlogoff | 1509633979.54881 |
| 1838323 | 2017-11-02 15:27:50 | 503   | agentlogoff | 1509636470.55125 |
| 1838373 | 2017-11-02 15:51:04 | 503   | agentlogin  | 1509637864.55274 |
| 1838385 | 2017-11-02 15:55:57 | 503   | agentlogoff | 1509638157.55318 |
| 1838460 | 2017-11-02 16:28:52 | 503   | agentlogin  | 1509640132.55533 |
| 1838472 | 2017-11-02 16:35:23 | 503   | agentlogoff | 1509640523.55564 |
| 1838499 | 2017-11-02 16:42:35 | 503   | agentlogin  | 1509640954.55630 |
| 1838567 | 2017-11-02 17:16:02 | 503   | agentlogoff | 1509642962.55820 |
| 1838686 | 2017-11-02 18:04:17 | 503   | agentlogoff | 1509645857.56162 |
| 1838861 | 2017-11-02 19:48:59 | 503   | agentlogoff | 1509652139.56778 |
| 1838896 | 2017-11-02 20:11:37 | 503   | agentlogoff | 1509653497.56914 |
+---------+---------------------+-------+-------------+------------------+

简而言之,我试图获得所有匹配对之间的总和秒数。我最接近的是

SELECT round(e2.uniqueid - e1.uniqueid) as seconds
FROM dumbtable e1
LEFT JOIN dumbtable e2
  ON e1.agent = e2.agent AND e2.etype ='agentlogoff' AND e1.calldate < e2.calldate
LEFT JOIN dumbtable e3
  ON e1.agent = e3.agent AND e1.calldate < e3.calldate AND e3.calldate < e2.calldate
WHERE e1.agent = '503' and e1.etype='agentlogin'
GROUP BY e1.agent;

...但这只是第一个匹配对的秒数而不是其他任何东西。


+---------+
| seconds |
+---------+
|     293 |
+---------+

非常感谢任何帮助

编辑:

见评论,(感谢沃尔特解决第一个问题!)我忘了展示一个能解决这两个问题的例子。除了仅通过登录解决登录对登录对之外,我还需要仅将登录的第一个实例与下一个登出实例进行比较,而不管其间的登录行。试图更清楚地描述,如果有

0退出 - &gt; 1次登录 - &gt; 2登录 - &gt; 3登录 - &gt; 4退出 - &gt; 5退出 - &gt; 6退出 - &gt;登录等

我希望在最后一次登出(4)时“配对”和timediff最早登录(1)并忽略2,3,5,6。我希望这是有道理的,这就是我应该如何制定我原来的问题。基本上,此表中唯一合法的时间戳是每次最早登录,然后是下一次最早的注销。

以下是多个登录行的示例。箭头是我在几秒钟内需要timediff的合法条目,其他一切都应该被忽略。

+---------+---------------------+-------+-------------+------------------+
| id      | calldate            | agent | etype       | uniqueid         |
+---------+---------------------+-------+-------------+------------------+
| 1838073 | 2017-11-02 13:21:00 | 503   | agentlogoff | 1509628860.54414 |x
| 1838232 | 2017-11-02 14:46:19 | 503   | agentlogoff | 1509633979.54881 |x
| 1838323 | 2017-11-02 15:27:50 | 503   | agentlogoff | 1509636470.55125 |x
| 1838373 | 2017-11-02 15:51:04 | 503   | agentlogin  | 1509637864.55274 |<--in
| 1838374 | 2017-11-02 15:52:04 | 503   | agentlogin  | 1509637866.55274 |x
| 1838375 | 2017-11-02 15:53:04 | 503   | agentlogin  | 1509637867.55274 |x
| 1838385 | 2017-11-02 15:55:57 | 503   | agentlogoff | 1509638157.55318 |<--out
| 1838460 | 2017-11-02 16:28:52 | 503   | agentlogin  | 1509640132.55533 |<--in
| 1838472 | 2017-11-02 16:35:23 | 503   | agentlogoff | 1509640523.55564 |<--out
| 1838499 | 2017-11-02 16:42:35 | 503   | agentlogin  | 1509640954.55630 |<--in
| 1838567 | 2017-11-02 17:16:02 | 503   | agentlogoff | 1509642962.55820 |<--out
| 1838686 | 2017-11-02 18:04:17 | 503   | agentlogoff | 1509645857.56162 |x
| 1838861 | 2017-11-02 19:48:59 | 503   | agentlogoff | 1509652139.56778 |x
| 1838896 | 2017-11-02 20:11:37 | 503   | agentlogoff | 1509653497.56914 |x
+---------+---------------------+-------+-------------+------------------+

另外,我希望我不是通过提出问题,获得完美答案,然后改变问题来违反规则。遗憾!!!

1 个答案:

答案 0 :(得分:0)

我最近几次遇到过这样的要求。这是我的评价:

如果您的id字段有自动增加选项,则下面的语句可以帮助您:

SELECT round(uniqueid2 - uniqueid1) AS seconds 
FROM
(
  SELECT uniqueid AS uniqueid1, 
         (SELECT uniqueid FROM dumbtable WHERE agent = '503' AND etype = 'agentlogoff' AND id > t1.id ORDER BY id LIMIT 1) AS uniqueid2 
  FROM dumbtable AS t1 WHERE agent = '503' AND etype = 'agentlogin'
) AS t;

这里的关键点是:

  • 使用Correlated Subquery,以便您可以为每个agentlogin记录重复执行此操作。
  • 使用自动增量id列和limit 1子语句找出准确的下一个匹配行(agentlogoff此处)。此处的自动增量字段不是必需的,在这种情况下您也可以使用calldate

对于第二个问题:
如果我是你,我会备份表,删除所有无效记录,然后运行我给你的第一个查询。它易于理解,易于实现,运行速度也更快。

删除无效记录:

DELETE 
FROM dumbtable AS t1 
WHERE etype = (SELECT etype FROM dumbtable WHERE id < t1.id ORDER BY id DESC LIMIT 1);

当然,我可以给你另一个查询来完成这项工作,但它会非常复杂,而且非常慢。