MySQL - 按日期时间段计算的峰值访问次数

时间:2016-07-04 23:47:49

标签: mysql

我有一个访问表(id int,start datetime,end datetime),我希望跟踪峰值访问次数。

示例数据:

+------+---------------------+---------------------+
| id   | date-time-1         | date-time-2         |
+------+---------------------+---------------------+
| 1059 | 2016-07-04 19:13:00 | 2016-07-04 19:20:05 |
| 1060 | 2016-07-04 19:13:30 | 2016-07-04 19:14:25 |
| 1061 | 2016-07-04 19:14:39 | 2016-07-04 19:20:05 |
| 1062 | 2016-07-05 02:34:40 | 2016-07-05 02:45:23 |
| 1063 | 2016-07-05 02:34:49 | 2016-07-05 02:45:34 |
+------+---------------------+---------------------+

预期结果应为:

+-------------------------------------------+-------+ 
| date-time-1         | date-time-2         | count | 
+-------------------------------------------+-------+ 
| 2016-07-04 19:13:00 | 2016-07-04 19:13:29 | 1     | 
| 2016-07-04 19:13:30 | 2016-07-04 19:14:25 | 2     | 
| 2016-07-04 19:14:26 | 2016-07-04 19:14:38 | 1     | 
| 2016-07-04 19:14:39 | 2016-07-04 19:20:05 | 2     | 
| 2016-07-04 19:20:06 | 2016-07-05 02:34:39 | 0     | 
| 2016-07-05 02:34:40 | 2016-07-05 02:34:48 | 1     | 
| 2016-07-05 02:34:49 | 2016-07-05 02:45:23 | 2     | 
| 2016-07-05 02:45:24 | 2016-07-05 02:45:34 | 1     | 
+------+------------------------------------+-------+

2 个答案:

答案 0 :(得分:0)

这不是很有效,但它会给你你的结果:

select U.dt1 as date-time-1, DATE_ADD(U.dt2,INTERVAL -1 SECOND) as date-time-2, 
    (select count(id) from Visits where 
    (dt1 >= u.dt1 and dt1<U.dt2)  --(dt1)dt2
    or (dt1<u.dt1 and dt2>=u.dt2)   -- dt1()dt2
    --or (dt2 >= u.dt1 and dt2<U.dt2) -- dt1(dt2) (comment this line to get your result which I believe is incorrect)
    ) as count 
from (
    select A.dt1 as dt1, (
        select min(M.dt) from ( select min(dt2) as dt from Visits where dt2 > A.dt1 union select min(dt1) as dt from Visits where dt1 > A.dt1) M
    ) as dt2 from Visits A
union 
    select B.dt2 as dt1, (
        select min(M.dt) from ( select min(dt2) as dt from Visits where dt2 > b.dt2 union select min(dt1) as dt from Visits where dt1 > b.dt2) M 
    ) as dt2 from Visits b where B.dt2 <> (select max(dt2) from Visits)
) U 

我已经评论了条件检查以查看访问是否在范围之前开始并在其中结束以获得与您相同的结果集,但我相信您应该考虑这一点。

答案 1 :(得分:0)

因此,为了完成这项工作,您需要了解您的期间和之间的重叠。我们在评论中同意,为了让它以正确的方式工作,你应该从第二行开始,至少有一秒加到前一端。为了理解我将添加一个图表,显示您的期间将如何以及正好在package -> socket.io-client表格的时间段之后,这样您最终会看到时间(因为所有期间都是同一天和小时,我将在图表上留下几分钟和几秒钟)

visits

为了实现这样的时间段,我创建了一个13:00 13:30 14:26 14:39 ^ ^ ^ ^ |------------||-----------||----------||-----------| |_ 13:31 |_ 14:25 |_ 14:40 |_ 20:05 --and in your table 13:00 20:05 ^ ^ |--------------------------------------------------| |------------| 14:39 20:05 |_ 13:30 |_ 14:25 ^ ^ |------------| 以方便查询,这里是代码:

VIEW

此观点的目的是确定您所定期间的所有日期create or replace view vw_times as select dtstart as dt from visits UNION select dtend as dt from visits; starts

以下是将产生此类时间段的查询:

ends

从中你可以SELECT case when cnt>1 then date_add(dtstart,interval 1 second) else dtstart end as dtstart, dtend from (SELECT dtstart, dtend, @ct:=@ct+1 as cnt FROM ( SELECT t1.dt as dtstart, (select min(x.dt) from vw_times as x where x.dt > t1.dt ) as dtend FROM vw_times t1, (select @ct := 0) as cttab ORDER BY t1.dt ) t2 WHERE dtend is not null ) as t3 你的桌子找到这样的重叠时期:

LEFT JOIN

这将导致:

SELECT times.dtstart, times.dtend, count(*)
  FROM (SELECT case when cnt>1 
                 then date_add(dtstart,interval 1 second) 
                 else dtstart 
                 end as dtstart,
               dtend
        from (SELECT dtstart, 
                     dtend, 
                     @ct:=@ct+1 as cnt
                FROM ( SELECT t1.dt as dtstart,
                              (select min(x.dt) 
                                 from vw_times as x
                                where x.dt > t1.dt
                               ) as dtend
                         FROM vw_times t1,
                              (select @ct := 0) as cttab
                        ORDER BY t1.dt
                      ) t2
                WHERE dtend is not null
              ) as t3
       ) as times 
       LEFT JOIN visits v 
              ON (    times.dtstart >= v.dtstart
                  AND times.dtend <= v.dtend)
 GROUP BY times.dtstart, times.dtend

在此处查看:http://sqlfiddle.com/#!9/3509ff/10

修改

由于您添加了带有最终结果的注释,因此最终查询会更小:

dtstart                      dtend                   count(*)
July, 04 2016 19:13:00       July, 04 2016 19:13:30     1
July, 04 2016 19:13:31       July, 04 2016 19:14:25     2
July, 04 2016 19:14:26       July, 04 2016 19:14:39     1
July, 04 2016 19:14:40       July, 04 2016 19:20:05     2

这将导致:

SELECT times.dtstart, 
       case when times.dtend = vmax.maxend
            then date_add(times.dtend, interval 1 second)
            else times.dtend
            end as dtend, 
       count(*)
  FROM  (SELECT dtstart, 
               dtend
          FROM ( SELECT t1.dt as dtstart,
                        (select min(date_sub(x.dt, interval 1 second)) 
                           from vw_times as x
                          where x.dt > t1.dt
                        ) as dtend
                   FROM vw_times t1
                  ORDER BY t1.dt
               ) t2
        WHERE t2.dtend is not null
       ) as times 
       LEFT JOIN visits as v
              ON (    times.dtstart >= v.dtstart
                  AND times.dtend <= v.dtend)
       LEFT JOIN (select max(date_sub(v.dtend, interval 1 second)) as maxend
                    from visits v) vmax
              ON ( times.dtend = vmax.maxend )
 GROUP BY times.dtstart, 
          case when times.dtend = vmax.maxend
            then date_add(times.dtend, interval 1 second)
            else times.dtend
            end

请在此处查看:http://sqlfiddle.com/#!9/3509ff/24