Search code examples
mysqldatetimerangechain

How do I find and group time chains in 36 seconds?


  • I have a date table.
  • I want to find and grouping dates with 36 seconds difference.
  • is there a difference of 36 seconds between the previous date and the next date?
  • If it is, it will be a group until the end of the chain.
  • If the 36-second chain is broken, it starts a new group.
  • if there is no chain for 36 seconds, finisDate and dateRangeIDs returns null

I can do this with software, but it is time consuming. I need to do over MySQL.

My date table (date > %d.%m.%Y %H:%i:%s);

ID  |   Date
----+-----------------------
246 |   11.08.2014 07:54:38
247 |   11.08.2014 07:55:11
248 |   11.08.2014 07:55:45
249 |   11.08.2014 07:56:20
250 |   11.08.2014 07:56:53
251 |   11.08.2014 07:57:26
252 |   11.08.2014 07:58:01
253 |   11.08.2014 07:58:35
254 |   11.08.2014 07:59:10
255 |   11.08.2014 07:59:49
256 |   11.08.2014 07:59:58
257 |   11.08.2014 08:00:15
258 |   11.08.2014 08:00:23
259 |   11.08.2014 08:00:58
260 |   11.08.2014 08:01:01
261 |   11.08.2014 08:01:08
262 |   11.08.2014 09:12:11

Expected result:

mainID  |   startDate               |   finishDate              |   dateRangeIDs
--------+---------------------------+---------------------------+-----------------
246     |   11.08.2014 07:54:38     |   11.08.2014 07:59:10     |   247,248,249,250,251,252,253,254 
255     |   11.08.2014 07:59:49     |   11.08.2014 08:01:08     |   256,257,258,259,260,261
262     |   11.08.2014 09:12:11     |   NULL                    |   NULL

Solution

  • The simplest method uses lag() to get the previous date value. That is not available in most versions of MySQL. A correlated subquery is really painful to make work. The last option is variables:

    select min(id) as mainid, min(date), max(date),
           group_concat(id order by id) as ids
    from (select t.*,
                 (@grp := if(@prev_date > date - interval 36 second,
                             if(@prev_date := date, @grp, @grp),  -- keep the group the same
                             if(@prev_date := date, @grp + 1, @grp + 1)
                            )
                 ) as grp
          from (select t.*
                from t
                order by date
               ) t cross join
               (select @prev_date := '', @grp := 0) params
         ) t
    group by grp;
    

    EDIT:

    You can remove the main id by doing:

    select min(id) as mainid, min(date), max(date),
           substr(group_concat(id order by id), length(min(id)) + 1) as ids