查询mysql一天中工作总时间的最佳方法

时间:2011-10-07 23:19:22

标签: mysql math time

我正在努力想出最好的方法来增加员工的总时间。

拳击类型日期,突破,中断&一天。您可能会认为我可以选择* where date = DATE,但如果员工在晚上11:30到达并在第二天凌晨2:00离开,则无效。

我认为这样的事情可能是最好的解决方案,但我不知道它是否实用甚至可能:

从LAST RECORD中选择*,其中employee = employee STOP在第一个“clock in”实例中。

这将收集员工上次入职以来的所有打击。例如:

ID NAME TYPE TIME

约翰时间45日

46 Joe Day In TIME

47 Mary Break Out TIME

48 Joe Break Out TIME

49 Joe Break In TIME

50 John Day Out Time

51 Mary Break In TIME

52 Joe Day Out TIME

53 Mary Day Out TIME

所以在我想到的例子中,如果你正在寻找Joe的时间,它将开始从冲头ID 53向后搜索,直到它达到46号冲头。结果将是拳46,48,49和51.我然后可以计算总工作时间。再说一次,我不知道这是否可能。

我真的很感谢有关如何完成此任务的任何意见/建议,或任何其他可能更实际的方法!

3 个答案:

答案 0 :(得分:2)

将问题分解为几个步骤,首先列出所有“IN”记录:

SELECT p_in.*
FROM punches p_in
WHERE p_in.type = 'IN'

接下来,编写子查询以查找下一个“OUT”记录(此方法假设为了简单起见,id会自动递增):

        SELECT MIN(pa.id)
        FROM punches pa
        WHERE pa.type = 'OUT'
        AND pa.name = p_in.name
        AND pa.time > p_in.time

现在,将此查询包装在外观选择中,该选择看起来像打孔表:

    SELECT pb.id, pb.name, pb.type, pb.time
    FROM punches pb
    WHERE pb.id = (
        SELECT MIN(pa.id)
        FROM punches pa
        WHERE pa.type = 'OUT'
        AND pa.name = p_in.name
        AND pa.time > p_in.time
    )

并在原始查询的LEFT JOIN中使用它:

SELECT
    p_in.id     in_id,
    p_in.name   in_name,
    p_in.type   in_type,
    p_in.time   in_time,
    p_out.id    out_id,
    p_out.name  out_name,
    p_out.type  out_type,
    p_out.time  out_time
FROM punches p_in
LEFT JOIN (
    SELECT pb.id, pb.name, pb.type, pb.time
    FROM punches pb
    WHERE pb.id = (
        SELECT MIN(pa.id)
        FROM punches pa
        WHERE pa.type = 'OUT'
        AND pa.name = p_in.name
        AND pa.time > p_in.time
    )
) p_out
WHERE p_in.type = 'IN'

这将为您提供一个结果集,其中每个“in”记录具有下一个相应的“out”记录。如果没有相应的out记录,则out值将设置为null。

希望您可以使用这些结果来计算您的需求。

答案 1 :(得分:0)

您已经拥有了员工ID,打卡类型ID,但您错过了日期或期间ID,这将使事情变得更加轻松:

PunchId  PeriodId  Employee  PunchTypeId  PunchDateTime
-------- --------- --------- ------------ --------------
...
44       1         Mary      Day In       TIME
45       1         John      Day In       TIME
46       1         Joe       Day In       TIME
47       1         Mary      Break Out    TIME
48       1         Joe       Break Out    TIME
49       1         Joe       Break In     TIME
50       1         John      Day Out      TIME
51       1         Mary      Break In     TIME
52       1         Joe       Day Out      TIME
53       1         Mary      Day Out      TIME
54       2         John      Day In       TIME
55       2         Mary      Day In       TIME
56       2         Joe       Day In       TIME
...

然后你可以使用类似的东西:

select di.Employee, di.PeriodId, 
    timediff(do.DayOutTime, bi.BreakInTime)
    + timediff(bo.BreakOutTime, di.DayInTime) as PeriodWorkedHours
from
(
    select Employee, PeriodId, PunchDateTime as DayInTime
    from punches
    where PunchTypeId = 'Day In'
) as di
inner join (
    select Employee, PeriodId, PunchDateTime BreakOutTime
    from punches
    where PunchTypeId = 'Break Out'
) as bo on di.Employee = bo.Employee and di.PeriodId = bo.PeriodId
inner join (
    select Employee, PeriodId, PunchDateTime as BreakInTime
    from punches
    where PunchTypeId = 'Break In'
) as bi on di.Employee = bi.Employee and di.PeriodId = bi.PeriodId
inner join (
    select Employee, PeriodId, PunchDateTime as DayOutTime
    from punches
    where PunchTypeId = 'Day Out'
) as do on di.Employee = do.Employee and di.PeriodId = do.PeriodId

假设在PeriodId中,所有员工每人都有四个拳(Day In,Break Out,Break In和Day Out)。此外,PeriodId不应与处理您在问题中提到的案例的日期相关联,当时打卡时间跨越日界限。而是在插入句点的最后一拳(即Day Out punch)后为员工增加PeriodId。

答案 2 :(得分:0)

我会像下一个一样使用查询:

select workerid, sum(case 
when punchtype = 'in' then -DATEDIFF(MINUTE, '20110901', punchtime)
when punchtype = 'out' then DATEDIFF(MINUTE, '20110901', punchtime)
when punchtype = 'bin' then -DATEDIFF(MINUTE, '20110901', punchtime)
when punchtype = 'bout' then DATEDIFF(MINUTE, '20110901', punchtime)
end )/60 as WorkingHours
from Punchlog
group by workerid

说明: 让我们假设我有桌子:

create table PunchLog
(workerid int not null,
punchtime datetime not null,
punchtype char(4) not null)

用几天的打孔数据。

让我们提供一些测试数据:

insert into PunchLog (workerid, punchtime, punchtype) values (1, '20110901 23:30', 'in')
insert into PunchLog (workerid, punchtime, punchtype) values (1, '20110902 03:30', 'out')
insert into PunchLog (workerid, punchtime, punchtype) values (1, '20110902 00:15', 'bin')
insert into PunchLog (workerid, punchtime, punchtype) values (1, '20110902 01:15', 'bout')
insert into PunchLog (workerid, punchtime, punchtype) values (2, '20110901 09:30', 'in')
insert into PunchLog (workerid, punchtime, punchtype) values (2, '20110901 17:00', 'out')
insert into PunchLog (workerid, punchtime, punchtype) values (2, '20110901 14:30', 'bin')
insert into PunchLog (workerid, punchtime, punchtype) values (2, '20110901 10:00', 'bout')

在工作场所度过的时间是:

T = out - in - (bin -bout) = out - in -bin + bout

其中inout是日期和binbout是打卡时间。

如果我将按workerid分组并将sum()应用于punchtime,那么我将有工作时间,但我需要in并且bin时间是否定的。我也无法总结日期时间。因此,我将punchtime更改为从过去的任何日期开始,并使用用例语句来设置符号:

sum(case 
when punchtype = 'in' then -DATEDIFF(MINUTE, '20110901', punchtime)
when punchtype = 'out' then DATEDIFF(MINUTE, '20110901', punchtime)
. . .
end )/60 as WorkingHours

在我的测试中它产生结果:

workerid  WorkingHours
--------  ------------
1         5
2         3