从签到日期列表中获取持续时间
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
| 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 join
和 not 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
我有一个用户的签到日期列表。 如何计算连续签入和签出之间的持续时间。 如果未找到结帐,请将持续时间保留为 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
| 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 join
和 not 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