我有一张桌子:
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标记,但这应该易于分组。
答案 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上进行检查