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

查询mysql一天工作总时间的最佳方法,mysql,math,time,Mysql,Math,Time,我正试图找到一种最好的方法来计算员工上班的总时间 冲床类型为每日冲床、休息冲床、休息冲床和休息冲床。你可能会认为我可以选择*where date=date,但如果员工在晚上11:30到达,第二天凌晨2:00离开,那就不行了 我在想这样的事情可能是最好的解决方案,但我不知道这是否可行: 从上次记录中选择*,其中employee=员工在第一次“打卡”时停止 这将收集自该员工上次打卡以来的所有信息。例如: ID名称类型时间 45约翰日 46乔一天的时间 玛丽休息时间到了 48乔出发时间 49乔磨合时间

我正试图找到一种最好的方法来计算员工上班的总时间

冲床类型为每日冲床、休息冲床、休息冲床和休息冲床。你可能会认为我可以选择*where date=date,但如果员工在晚上11:30到达,第二天凌晨2:00离开,那就不行了

我在想这样的事情可能是最好的解决方案,但我不知道这是否可行:

从上次记录中选择*,其中employee=员工在第一次“打卡”时停止

这将收集自该员工上次打卡以来的所有信息。例如:

ID名称类型时间

45约翰日

46乔一天的时间

玛丽休息时间到了

48乔出发时间

49乔磨合时间

每天外出50小时

玛丽准时到达

52乔白天休息时间

53玛丽白天外出时间

所以在我想的例子中,如果你在寻找Joe的时间,它会从PunchID53开始向后搜索,直到找到Punch46。结果将是冲头46、48、49和51。然后我可以计算出工作的总时间。再说一遍,我不知道这是否可能


我非常感谢您对如何实现这一目标提出的任何意见/建议,或任何其他更实际的方法

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

SELECT p_in.*
FROM punches p_in
WHERE p_in.type = 'IN'
接下来,编写一个子查询以查找下一个“OUT”记录(为了简单起见,此方法假设id是自动递增的):

现在,将此查询包装在一个类似于Punchs表的外部选择中:

    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
    )
并在与原始查询的左联接中使用:

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


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

您已经有了员工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 ...
这是假设在一个PeriodId内,所有员工每人有四次打孔(每天打孔、休息、休息和休息)。此外,当打卡时间跨越日边界时,PeriodId不应与处理问题中提到的案例的日期绑定。相反,在插入该期间的最后一个打孔(即,日外打孔)后,增加员工的PeriodId。

我将使用如下查询:

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
其中,
in
out
是日打卡时间,
bin
bout
是中断打卡时间

如果我将按
workerid
分组,并将sum()应用于
punchtime
,则我将有工作时间,但我需要
中的
,而
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

如果数据库的结构有所不同,那就更好了。当有人打卡时,你会记录下来,当有人打卡时,你会找到他们最近的打卡时间,并在其中添加一个打卡时间。但我认为这超出了你的控制范围,或者它有不同的理由以这种方式构建。我同意@Jefromi。更改数据库的结构将使系统更易于使用。这也使得人们更容易发现忘记打卡的情况。虽然这可能不在你的控制之下。我会以任何需要的方式重组它。。。这就是为什么我要求任何其他建议。什么是最好的???@user971230:我不是数据库设计专家,我也不知道你的所有要求,但如果你的主要要求是知道人们在那里呆了多久,那么我在第一条评论中建议的结构是一个合理的起点。它会更简单,但我需要跟踪是休息还是休息。我需要能够查看员工是否在白天或休息时被打卡。PS-这是我问题的一部分-我如何找到最近的打卡?哇。。。这看起来很神奇,但我很难理解。mysql字段是“punch_id”(自动递增)、“emp_id”(员工id)、punch_类型、punch_时间(时间戳)。我试图更新我的PHP页面以使用您提供的代码,但是您的示例中的名称让我有点困惑。您能建议如何使用我提供的字段名来执行此操作吗?我将不胜感激!这可能导致的一个问题是,一天中可能不会有四次打孔。员工不得休息。不过,我会仔细研究一下,谢谢你的建议。周期ID的想法让我思考。。。
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