MySQL Group from quarters to periods

半腔热情 提交于 2021-01-28 06:02:22

问题


I have a table like this:

Person smallint(5)  act_time datetime
1   2020-05-29 07:00:00
1   2020-05-29 07:15:00
1   2020-05-29 07:30:00
2   2020-05-29 07:15:00
2   2020-05-29 07:30:00
1   2020-05-29 10:30:00
1   2020-05-29 10:45:00

The table above is an example with 2 different persons and there is a row for each quarter they are at work...

What is the best way in MySQL to "convert" this table to another table where there is a column for "person", a column for "start" and one for "stop".

So the result is like:

Person  Start   Stop
1   2020-05-29 07:00:00   2020-05-29 07:45:00
2   2020-05-29 07:15:00   2020-05-29 07:45:00
1   2020-05-29 10:30:00   2020-05-29 11:00:00

I have tried with a left join to the same original table but it didn't work...

Thanks.

Thanks for your reply. I have now tried it with the table above - and it unfortunately doesn't give that result... My sql string is:

select person,min(act_time) start_date,max(act_time) end_date from (select t.*,row_number() over(order by act_time) rn1,row_number() over(partition by person order by act_time) rn2 from test t) t group by person, rn1 - rn2 order by min(act_time)

But the result it generates is:
1 29-05-2020 07:00:00 29-05-2020 07:15:00
2 29-05-2020 07:15:00 29-05-2020 07:15:00
1 29-05-2020 07:30:00 29-05-2020 07:30:00
2 29-05-2020 07:30:00 29-05-2020 07:30:00
1 29-05-2020 10:30:00 29-05-2020 10:45:00

It should be like the result with 3 rows. So when there is a gap in more than 15 minutes between to rows with the same person it should create a new row.


回答1:


This is a gaps and islands problem. You can solve it with window functions (available in MySQL 8.0 only):

select 
    person,
    min(act_date) start_date,
    max(act_date) end_date
from (
    select
        t.*,
        sum(act_date <> lag_act_date + interval 15 minute)
            over(partition by person order by act_date) grp
    from (
        select 
            t.*,
            lag(act_date) 
                over(partition by person order by act_date) lag_act_date
        from mytable t
    ) t
) t
group by person, grp
order by min(act_date)

The idea is to build groups of adjacent records using a cumulative sum: every time there is a gap that is not 15 minutes, the sum increments.




回答2:


This is a gaps-and-islands problem. I'm not sure why GMB's solution doesn't work, but this should:

select person, min(act_date) as start_date,
       max(act_date) + interval 15 minute as end_date
from (select t.*,
             sum(case when prev_act_date >= act_date - interval 15 minute then 0 else 1 end) over
                 (partition by person order by act_date) as grp
      from (select t.*,
                   lag(act_date) over (partition by person order by act_date) as prev_act_date
            from t
           ) t
     ) t
group by person, grp
order by min(act_date)


来源:https://stackoverflow.com/questions/62082968/mysql-group-from-quarters-to-periods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!