【问题标题】:Best way to query mysql for total time worked in a day查询mysql一天总工作时间的最佳方法
【发布时间】:2011-10-13 01:37:56
【问题描述】:

我正在尝试找出添加员工打卡总时间的最佳方法。

打孔类型为日间、休息、休息和休息。你会认为我可以只选择 * where date = DATE,但如果员工在晚上 11:30 到达并在第二天凌晨 2:00 离开,这将不起作用。

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

从 LAST RECORD 中选择 *,其中员工 = 员工在第一次“打卡”时停止。

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

ID 名称类型时间

45 John Day In TIME

46 乔日在时间

47 玛丽爆发时间

48 乔休息时间

49 乔闯入时间

50 John Day Out TIME

51 玛丽闯关时间

52 乔外出时间

53 玛丽节外出时间

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

我非常感谢任何有关如何完成此操作的 cmets/建议,或任何其他可能更实际的方法!

【问题讨论】:

  • 如果数据库的结构不同似乎会很好。当有人打卡时,您会记录下来,当有人打卡时,您会找到他们最近的打卡时间并为其添加外出时间。但我认为这超出了你的控制范围,或者有不同的理由采用这种结构。
  • 我同意@Jefromi。更改数据库的结构将使系统更易于使用。它还可以更容易地找到人们忘记打卡的情况。虽然这可能不在你的控制范围内。
  • 我会以任何需要的方式对其进行重组......这就是我要求任何其他建议的原因。什么是最好的???
  • @user971230:我不是数据库设计专家,我不知道你的所有要求,但如果你的主要要求是知道人们在那里呆了多久,我在我的建议中建议的结构第一条评论是一个合理的起点。
  • 这会更简单,但我需要跟踪它是休息打卡还是一天打卡。我需要能够查看员工是在当天下班还是在休息时间。 PS-这是我的问题的一部分-我如何找到最近的打卡?

标签: mysql math time


【解决方案1】:

将问题分解为步骤,首先列出所有“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'

这将为您提供一个结果集,其中每个“输入”记录都有下一个对应的“输出”记录。如果没有对应的输出记录,输出值将被设置为null。

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

【讨论】:

  • 哇...这看起来很棒,但我很难理解这个问题。 mysql 字段是“punch_id”(自动增量)、“emp_id”(员工 id)、punch_type、punch_time(时间戳)。我正在尝试更新我的 PHP 页面以使用您提供的代码,但您示例中的名称让我有点困惑。您能否建议如何使用我提供的字段名称来执行此操作?我将不胜感激!
【解决方案2】:

您已经有了员工 ID、打卡类型 ID,但是您缺少日期或期间 ID,这将使事情变得容易得多:

PunchId PeriodId 员工 PunchTypeId PunchDateTime -------- --------- --------- ------------ ------------ -- ... 44 1 时间中的玛丽日 45 1 约翰·戴及时 46 1乔日在时间 47 1 玛丽爆发时间 48 1乔突破时间 49 1乔打破时间 50 1 约翰外出时间 51 1 玛丽闯关时间 52 1 乔外出时间 53 1 玛丽节外出时间 54 2 约翰·戴及时 55 2 时间中的玛丽日 56 2乔日在时间 ...

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

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 打卡)后,为员工增加 PeriodId。

【讨论】:

  • 这可能导致的一个问题是一天可能没有四拳。员工不得休息。不过我会仔细研究一下,谢谢你的建议。时期 ID 的想法让我思考......
【解决方案3】:

我会使用如下查询:

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 那么我将有工作时间但我需要 inbin 时间是负数。我也不能总结日期时间。因此,我会将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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多