从签到日期列表中获取持续时间

Get durations from list of checkin dates

我有一个用户的签到日期列表。 如何计算连续签入和签出之间的持续时间。 如果未找到结帐,请将持续时间保留为 0

+----+-----------+---------------------+
| ID | isCheckIn |     DateChecked     |
+----+-----------+---------------------+
| 1  |     1     | 2019-10-08 10:22:15 | 
| 2  |     0     | 2019-10-08 10:24:30 | 
| 3  |     1     | 2019-10-08 10:27:01 | 
| 4  |     1     | 2019-10-08 10:31:44 | 
| 5  |     0     | 2019-10-08 10:50:56 | 
| 6  |     1     | 2019-10-09 09:24:09 | 
| 7  |     0     | 2019-10-09 09:35:59 | 
| 8  |     1     | 2019-10-09 10:04:26 | 
+----+-----------+---------------------+

我期待这样的事情(持续时间以分钟为单位)...

+---------------------+---------------------+----------+
|      CheckIn        |       CheckOut      | Duration |
+---------------------+---------------------+----------+
| 2019-10-08 10:22:15 | 2019-10-08 10:24:30 |    2     |
| 2019-10-08 10:27:01 |                     |    0     |
| 2019-10-08 10:31:44 | 2019-10-08 10:50:56 |    19    |
| 2019-10-09 09:24:09 | 2019-10-09 09:35:59 |    11    |
| 2019-10-09 10:04:26 |                     |    0     |
+---------------------+---------------------+----------+

我解决了获取列表、遍历列表、创建几个日期和计算时差的问题,但我更喜欢在服务器端做更多事情。 有什么建议吗?非常感谢!!!

在 MySQL 8.0 中,您可以使用 lead():

来解决这个问题
select
    DateChecked CheckIn,
    case 
        when leadIsCheckIn = 0 then leadDateChecked 
    end CheckOut,
    case 
        when leadIsCheckIn = 0 then timestampdiff(minute, DateChecked, leadDateChecked) 
        else 0 
    end Duration
from (
    select
        DateChecked,
        isCheckIn ,
        lead(DateChecked) over(order by DateChecked) leadDateChecked,
        lead(isCheckIn) over(order by DateChecked) leadIsCheckIn
    from mytable
) x
where isCheckIn = 1
order by DateChecked 

Demo on DB Fiddle:

| CheckIn             | CheckOut            | Duration |
| ------------------- | ------------------- | -------- |
| 2019-10-08 10:22:15 | 2019-10-08 10:24:30 | 2        |
| 2019-10-08 10:27:01 |                     | 0        |
| 2019-10-08 10:31:44 | 2019-10-08 10:50:56 | 19       |
| 2019-10-09 09:24:09 | 2019-10-09 09:35:59 | 11       |
| 2019-10-09 10:04:26 |                     | 0        |

在早期版本中,您可以在相关子查询上使用自 left joinnot exists 条件模拟 lead()

select
    t.DateChecked CheckIn,
    tlead.DateChecked CheckOut,
    coalesce(timestampdiff(minute, t.DateChecked, tlead.DateChecked), 0) Duration
from mytable t
left join mytable tlead
    on tlead.DateChecked > t.DateChecked
    and tlead.isCheckIn = 0
    and not exists (
        select 1
        from mytable t1
        where 
            t1.DateChecked > t.DateChecked 
            and t1.DateChecked < tlead.DateChecked
    )
where t.isCheckIn = 1
order by t.DateChecked 

Demo on DB Fiddle: 结果同上

在 mysql 5.7 作品中

SELECT 
  MIN(`DateChecked`) CheckIn
  , MAX(`DateChecked`) CheckOut
  ,timestampdiff(MINUTE,MIN(`DateChecked`), MAX(`DateChecked`)) duration
FROM
  (SELECT 
  `DateChecked`,
  if (isCheckIn = 1,@group1 := @group1  + 1,@group1 := @group1 ) group1
  FROM
    duration, (SELECT @group1 := 0) g
  ORDER BY `DateChecked` ASC
) t1
GROUP by group1
ORDER BY CheckIn;

结果就是

CheckIn                 CheckOut                duration
2019-10-08 10:22:15     2019-10-08 10:24:30     2
2019-10-08 10:27:01     2019-10-08 10:27:01     0
2019-10-08 10:31:44     2019-10-08 10:50:56     19
2019-10-09 09:24:09     2019-10-09 09:35:59     11
2019-10-09 10:04:26     2019-10-09 10:04:26     0

请在此处查看示例 https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=442c13184b01af2b6e079b80815046fb