SQL 表示员工签到和签退的查询 - 白天和晚上的工作时间
SQL Query to represent employee check-in and check-out - Working Hours in a day and nights
我table记录为
id | int
badge_id | varchar
status | enum('check_in','check_out')
timestamp | datetime
数据库有数据为
id badge_id status Timestamp
1 EMP0001 check_in 2021-11-22 08:00:00
2 EMP0002 check_in 2021-11-22 08:00:50
3 EMP0001 check_out 2021-11-22 13:00:00
4 EMP0002 check_out 2021-11-22 13:01:00
5 EMP0001 check_in 2021-11-22 13:31:00
6 EMP0002 check_in 2021-11-22 13:33:50
7 EMP0001 check_out 2021-11-22 18:03:00
8 EMP0002 check_out 2021-11-22 18:04:00
9 EMP0003 check_in 2021-11-22 17:00:00
10 EMP0004 check_in 2021-11-22 19:00:50
11 EMP0003 check_out 2021-11-22 21:30:00
12 EMP0004 check_out 2021-11-23 00:22:00
13 EMP0003 check_in 2021-11-22 22:01:00
14 EMP0004 check_in 2021-11-23 00:55:50
15 EMP0003 check_out 2021-11-23 03:30:00
16 EMP0004 check_out 2021-11-23 05:38:00
白班和夜班(第二天结束)
我正在努力让他们每个人的工作时间都适合白班,但现在也可以在夜班工作。有什么建议吗?
要获取的代码:
SELECT
id,
MIN(timestamp) AS check_in_at,
MAX(timestamp) AS check_out_at,
TIMESTAMPDIFF(MINUTE, MIN(timestamp), MAX(timestamp))/60 AS total_time
FROM cte where timestamp BETWEEN '2021-12-27' AND '2021-12-30'
GROUP BY
badge_id,date(timestamp)
ORDER BY
badge_id,timestamp;
预期结果:
badge_id Check_in_at Check_out_at Total_time
EMP0001 2021-11-22 08:00:00 2021-11-22 18:03:00 7.9500
EMP0002 2021-11-22 08:00:50 2021-11-22 18:04:00 7.9833
EMP0003 2021-11-22 17:00:00 2021-11-23 03:30:00 10.3000
EMP0004 2021-11-22 19:00:00 2021-11-23 05:38:00 10.3800
有人可以建议我查询吗?
我无法完全匹配您的预期输出,因为我不明白(例如)2021-11-22 08:00:00 2021-11-22 18:03:00
是 7.95 小时,而根据我的计算是 10.05 小时。此外,白天有一个 check_in/out 完成,因此有 2 种可能的计算,一种排除休息时间,另一种忽略休息时间。
请注意,我已选择在第一个 cte 中使用 correlated subqueries
以在 1 天的时间间隔内将最早签到与最新签出对齐,从而使最终结果允许跨越午夜的班次。另请注意,限制数据日期范围的 where 子句应出现在第一个 cte 中。
with cte as (
select distinct
t.badge_id
, (select min(s.timestamp)
from mytable s
where t.badge_id = s.badge_id and t.timestamp > date_sub(s.timestamp,interval 1 day)
) check_in_at
, (select max(s.timestamp)
from mytable s
where t.badge_id = s.badge_id and t.timestamp < date_add(s.timestamp,interval 1 day)
) check_out_at
from mytable t
/* where t.timestamp >= '2021-12-27' and t.timestamp < '2022-01-01' */
)
select
badge_id
, check_in_at
, check_out_at
, TIMESTAMPDIFF(MINUTE, check_in_at, check_out_at)/60 AS total_time
from cte
order by
badge_id
, check_in_at
结果(来自示例数据)是:
+----------+---------------------+---------------------+------------+
| badge_id | check_in_at | check_out_at | total_time |
+----------+---------------------+---------------------+------------+
| EMP0001 | 2021-11-22 08:00:00 | 2021-11-22 18:03:00 | 10.0500 |
| EMP0002 | 2021-11-22 08:00:50 | 2021-11-22 18:04:00 | 10.0500 |
| EMP0003 | 2021-11-22 17:00:00 | 2021-11-23 03:30:00 | 10.5000 |
| EMP0004 | 2021-11-22 19:00:50 | 2021-11-23 05:38:00 | 10.6167 |
+----------+---------------------+---------------------+------------+
db<>fiddle here
上一个请求的查询(产生不同的结果):
with cte1 as (
select
t.id
, t.badge_id
, t.timestamp as check_in_at
, (select o.timestamp from mytable as o
where t.status = 'check_in' and o.status = 'check_out'
and o.badge_id = t.badge_id
and o.timestamp > t.timestamp
order by timestamp
limit 1)
as check_out_at
from mytable t
/* where timestamp BETWEEN '2021-12-27' AND '2021-12-30' */
)
, cte as (
select
*
, TIMESTAMPDIFF(MINUTE, check_in_at, check_out_at)/60 AS total_time
from cte1
where check_out_at is not null
)
SELECT
badge_id
, date(check_in_at) AS date_check_in
, MIN(check_in_at) AS check_in_at
, MAX(check_out_at) AS check_out_at
, SUM(total_time) as total_time_with_break
, TIMESTAMPDIFF(MINUTE, MIN(check_in_at), MAX(check_out_at))/60 AS total_time_no_break
FROM cte
GROUP BY
badge_id, date(check_in_at)
ORDER BY
badge_id, date(check_in_at)
我table记录为
id | int
badge_id | varchar
status | enum('check_in','check_out')
timestamp | datetime
数据库有数据为
id badge_id status Timestamp
1 EMP0001 check_in 2021-11-22 08:00:00
2 EMP0002 check_in 2021-11-22 08:00:50
3 EMP0001 check_out 2021-11-22 13:00:00
4 EMP0002 check_out 2021-11-22 13:01:00
5 EMP0001 check_in 2021-11-22 13:31:00
6 EMP0002 check_in 2021-11-22 13:33:50
7 EMP0001 check_out 2021-11-22 18:03:00
8 EMP0002 check_out 2021-11-22 18:04:00
9 EMP0003 check_in 2021-11-22 17:00:00
10 EMP0004 check_in 2021-11-22 19:00:50
11 EMP0003 check_out 2021-11-22 21:30:00
12 EMP0004 check_out 2021-11-23 00:22:00
13 EMP0003 check_in 2021-11-22 22:01:00
14 EMP0004 check_in 2021-11-23 00:55:50
15 EMP0003 check_out 2021-11-23 03:30:00
16 EMP0004 check_out 2021-11-23 05:38:00
白班和夜班(第二天结束)
我正在努力让他们每个人的工作时间都适合白班,但现在也可以在夜班工作。有什么建议吗?
要获取的代码:
SELECT
id,
MIN(timestamp) AS check_in_at,
MAX(timestamp) AS check_out_at,
TIMESTAMPDIFF(MINUTE, MIN(timestamp), MAX(timestamp))/60 AS total_time
FROM cte where timestamp BETWEEN '2021-12-27' AND '2021-12-30'
GROUP BY
badge_id,date(timestamp)
ORDER BY
badge_id,timestamp;
预期结果:
badge_id Check_in_at Check_out_at Total_time
EMP0001 2021-11-22 08:00:00 2021-11-22 18:03:00 7.9500
EMP0002 2021-11-22 08:00:50 2021-11-22 18:04:00 7.9833
EMP0003 2021-11-22 17:00:00 2021-11-23 03:30:00 10.3000
EMP0004 2021-11-22 19:00:00 2021-11-23 05:38:00 10.3800
有人可以建议我查询吗?
我无法完全匹配您的预期输出,因为我不明白(例如)2021-11-22 08:00:00 2021-11-22 18:03:00
是 7.95 小时,而根据我的计算是 10.05 小时。此外,白天有一个 check_in/out 完成,因此有 2 种可能的计算,一种排除休息时间,另一种忽略休息时间。
请注意,我已选择在第一个 cte 中使用 correlated subqueries
以在 1 天的时间间隔内将最早签到与最新签出对齐,从而使最终结果允许跨越午夜的班次。另请注意,限制数据日期范围的 where 子句应出现在第一个 cte 中。
with cte as (
select distinct
t.badge_id
, (select min(s.timestamp)
from mytable s
where t.badge_id = s.badge_id and t.timestamp > date_sub(s.timestamp,interval 1 day)
) check_in_at
, (select max(s.timestamp)
from mytable s
where t.badge_id = s.badge_id and t.timestamp < date_add(s.timestamp,interval 1 day)
) check_out_at
from mytable t
/* where t.timestamp >= '2021-12-27' and t.timestamp < '2022-01-01' */
)
select
badge_id
, check_in_at
, check_out_at
, TIMESTAMPDIFF(MINUTE, check_in_at, check_out_at)/60 AS total_time
from cte
order by
badge_id
, check_in_at
结果(来自示例数据)是:
+----------+---------------------+---------------------+------------+
| badge_id | check_in_at | check_out_at | total_time |
+----------+---------------------+---------------------+------------+
| EMP0001 | 2021-11-22 08:00:00 | 2021-11-22 18:03:00 | 10.0500 |
| EMP0002 | 2021-11-22 08:00:50 | 2021-11-22 18:04:00 | 10.0500 |
| EMP0003 | 2021-11-22 17:00:00 | 2021-11-23 03:30:00 | 10.5000 |
| EMP0004 | 2021-11-22 19:00:50 | 2021-11-23 05:38:00 | 10.6167 |
+----------+---------------------+---------------------+------------+
db<>fiddle here
上一个请求的查询(产生不同的结果):
with cte1 as (
select
t.id
, t.badge_id
, t.timestamp as check_in_at
, (select o.timestamp from mytable as o
where t.status = 'check_in' and o.status = 'check_out'
and o.badge_id = t.badge_id
and o.timestamp > t.timestamp
order by timestamp
limit 1)
as check_out_at
from mytable t
/* where timestamp BETWEEN '2021-12-27' AND '2021-12-30' */
)
, cte as (
select
*
, TIMESTAMPDIFF(MINUTE, check_in_at, check_out_at)/60 AS total_time
from cte1
where check_out_at is not null
)
SELECT
badge_id
, date(check_in_at) AS date_check_in
, MIN(check_in_at) AS check_in_at
, MAX(check_out_at) AS check_out_at
, SUM(total_time) as total_time_with_break
, TIMESTAMPDIFF(MINUTE, MIN(check_in_at), MAX(check_out_at))/60 AS total_time_no_break
FROM cte
GROUP BY
badge_id, date(check_in_at)
ORDER BY
badge_id, date(check_in_at)