计算工作时间两行之间的时差

时间:2018-08-03 16:43:11

标签: mysql

我有一张桌子:

timedate                 workclock
2018-01-01 09:00:00      check-in
2018-01-01 12:30:40      check-in
2018-01-02 09:00:00      check-in
2018-01-02 11:29:00      check-out
2018-01-03 14:29:00      check-out

我需要输出看起来像这样:

date          checkin      checkout     working-time
2018-01-01    09:00        none         missing checkout
2018-01-02    09:00        11:29        02:29
2018-01-03    none         14:29        missing checkin

我无法加入行,因此我们将不胜感激 还有第三个col代表worker标记,但这应该易于分组。

2 个答案:

答案 0 :(得分:1)

可能有更好的方法来执行此操作,但是这是作为三部分查询来执行的操作。

首先,找到所有签到位置,然后使用子查询选择同一天签到之后的第一个签出位置。

select
    date(t1.timedate) as date,
    time(t1.timedate) as checkin,
    (
        select time(t2.timedate)
        from timetracker t2
        where workclock = 'check-out'
          and date(t2.timedate) = date(t1.timedate)
          and t1.timedate < t2.timedate
     ) as checkout
from timetracker t1
where t1.workclock = 'check-in'

+------------+----------+----------+
| date       | checkin  | checkout |
+------------+----------+----------+
| 2018-01-01 | 09:00:00 | NULL     |
| 2018-01-01 | 12:30:40 | NULL     |
| 2018-01-02 | 09:00:00 | 11:29:00 |
+------------+----------+----------+

注意:我假设您缺少集合中的12:30:40行。

然后在一个单独的查询中,找到所有没有签入的签出。这是通过对签入行进行自联接完成的。

select
    date(t3.timedate) as date,
    null as checkin,
    time(t3.timedate) as checkout
from timetracker t3
left join timetracker t4
     on date(t3.timedate) = date(t4.timedate) and
        t4.workclock = 'check-in'
where t3.workclock = 'check-out'
  and t4.timedate is null

+------------+---------+----------+
| date       | checkin | checkout |
+------------+---------+----------+
| 2018-01-03 |    NULL | 14:29:00 |
+------------+---------+----------+

union一起。

select
    date(t1.timedate) as date,
    time(t1.timedate) as checkin,
    (
        select time(t2.timedate)
        from timetracker t2
        where workclock = 'check-out'
          and date(t2.timedate) = date(t1.timedate)
          and t1.timedate < t2.timedate
        order by t2.timedate
        limit 1
     ) as checkout
from timetracker t1
where t1.workclock = 'check-in'

union

select
    date(t3.timedate) as date,
    null as checkin,
    time(t3.timedate) as checkout
from timetracker t3
left join timetracker t4
     on date(t3.timedate) = date(t4.timedate) and
        t4.workclock = 'check-in'
where t3.workclock = 'check-out'
    and t4.timedate is null

+------------+----------+----------+
| date       | checkin  | checkout |
+------------+----------+----------+
| 2018-01-01 | 09:00:00 | NULL     |
| 2018-01-01 | 12:30:40 | NULL     |
| 2018-01-02 | 09:00:00 | 11:29:00 |
| 2018-01-03 | NULL     | 14:29:00 |
+------------+----------+----------+

最后一部分是格式和排序。与其尝试在已经非常庞大的查询中执行此操作,不如针对格式进行新查询。将此查询用作子查询表。

select
    t.date,
    case
    when t.checkin is null then
        'none'
    else
        t.checkin
    end as "checkin",
    case
    when t.checkout is null then
        'none'
    else
        t.checkout
    end as "checkout",
    case
    when checkout is null then
        'missing checkout'
    when checkin is null then
        'missing checkin'
    else
        time(checkout - checkin)
    end as "working-time"
from (
    select ...
    union
    select ...
) t
order by t.date, t.checkin

+------------+----------+----------+------------------+
| date       | checkin  | checkout | working-time     |
+------------+----------+----------+------------------+
| 2018-01-01 | 09:00:00 | none     | missing checkout |
| 2018-01-01 | 12:30:40 | none     | missing checkout |
| 2018-01-02 | 09:00:00 | 11:29:00 | 02:29:00         |
| 2018-01-03 | none     | 14:29:00 | missing checkin  |
+------------+----------+----------+------------------+

或者省去一些麻烦,然后在接收端进行格式化。

答案 1 :(得分:1)

使用视图可简化查询,因此请使用

Promise.all

然后使用以下查询

create view in_gate_times as
select date(date_time) xdate, time(date_time) xtime
  from gate_times where gate_op = 'check-in';

create view out_gate_times as
select date(date_time) xdate, time(date_time) xtime
  from gate_times where gate_op = 'check-out';

SQLFiddle上进行检查

如果使用select i.xdate, i.xtime, ifnull(o.xtime, 'missing') from in_gate_times i left join out_gate_times o on i.xdate = o.xdate union select o.xdate, ifnull(i.xtime, 'missing'), o.xtime from in_gate_times i right join out_gate_times o on i.xdate = o.xdate order by 1, 2, 3 使查询变慢,请使用union进行以下更改

union all

SQLFiddle上选中此项


如果禁止使用视图,只需将每个视图替换为其查询,这样最后一个查询将是

select i.xdate, i.xtime, ifnull(o.xtime, 'missing')
  from in_gate_times i
  left join out_gate_times o on i.xdate = o.xdate
 union all
select o.xdate, ifnull(i.xtime, 'missing'), o.xtime
  from in_gate_times i
 right join out_gate_times o on i.xdate = o.xdate
 where i.xdate is null
 order by 1, 2, 3

可以在SQLFiddle上进行检查