问题
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