所以,我们有一个名为timePunches
的表:
CREATE TABLE `timePunches` (
`punchID` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'The unique ID of the punch',
`employeeID` VARCHAR(50) NOT NULL COMMENT 'Who did the punch',
`punchDATETIME` DATETIME NOT NULL COMMENT 'The time of the punch',
`punchDTC_LINK` DATETIME NULL DEFAULT NULL COMMENT 'The previous start time for the OUT punch',
`punchDATECRC` INT(100) NOT NULL COMMENT 'The punch CRC, to prevent hacking',
`punchDIRECTION` TINYTEXT NOT NULL COMMENT 'What the punch did',
`punchTOTAL` INT(11) NULL DEFAULT NULL,
`fullName` TEXT NULL,
PRIMARY KEY (`punchID`)
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM
ROW_FORMAT=DYNAMIC
AUTO_INCREMENT=15825
此表用于跟踪员工的打卡时间。这意味着,我们会跟踪他们何时打并点击 。此表是审计合规性表,这意味着我们不会 SELECT / UPDATE 记录,而是仅 SELECT / INSERT 。
所以,当用户敲击时钟时会发生这种情况:
PUNCH IN:应用程序发送employeeID
(字符串),punchDATETIME
(日期时间),punchDATECRC
(int)和punchDTC_LINK
(DateTime [null])通过存储过程到数据库。此存储过程将必要的信息添加到数据库,以包括触发内部函数以将用户的全名拉入同一个表中。
PUNCH OUT :应用程序发送employeeID
(字符串),punchDATETIME
(日期时间),punchDATECRC
(int)和punchDTC_LINK
(DateTime)到数据库。存储过程添加必要的信息,包括在两个DateTime
元素之间进行数学运算的触发器,并填写合法名称。
从上面我们可以看到,当用户点击 IN 时,查询看起来像这样:
INSERT INTO
timePunches
(punchID
,employeeID
,punchDATETIME
,punchDTC_LINK
,punchDATECRC
,punchDIRECTION
,{{1 }})VALUES(15797,'prumple','2012-01-11 17:35:10',NULL,-2011509138,'IN',NULL);
并且,当用户打出 out 时,它会发送如下内容:
INSERT INTO
punchTOTAL
(timePunches
,punchID
,employeeID
,punchDATETIME
,punchDTC_LINK
,punchDATECRC
,{{1 }})VALUES(15797,'prumple','2012-01-11 19:39:52','2012-01-11 17:35:10',-2011509138,'OUT',NULL);
因此,正如我们所看到的,DataTable中有2个元素供该用户使用。一个punchDIRECTION
和一个punchTOTAL
。
我需要做的是找出用户是否忘记了IN
。所以,让我们假设一个用户打出OUT
,一整天都在工作,关闭他们的时钟,然后在第二天再次击打OUT
。然后,他完成了全班工作,并记得这次打IN
。
现在,在这种情况下,我们有2 IN
拳,只有1 out
拳。我需要一种方法来检测它。
答案 0 :(得分:1)
你说“你看,当用户打入时,它会填充所有必要的数据,但punchDTC_LINK字段除外;这会留下'null',因为该字段用于之前的开始时间。”
这应该意味着你可以做WHERE punchDIRECTION = "IN" AND punchDTC_LINK = NULL
答案 1 :(得分:1)
如果我理解正确,“IN”记录的相应“OUT”记录将匹配employeeID
(该记录针对的是同一名员工),“IN”DATETIME
将匹配“OUT” 'DTC_LINK
。
-- Fetch all 'IN' records without a corresponding 'OUT'
SELECT tp_in.*
FROM timePunches tp_in
LEFT JOIN timePunches tp_out
ON tp_in.employeeID = tp_out.employeeID
AND
tp_in.punchDATETIME = tp_out.punchDTC_LINK
WHERE tp_in.punchDIRECTION = 'IN'
AND
tp_out.punchDTC_LINK IS NULL;
答案 2 :(得分:0)
你会把表连接到外部:
select
a.punchId
from
timePunches a
left outer join timePunches b on
a.punchId = b.punchDTC_LINK
where
b.punchDTC_LINK is null
and a.punchDirection = 'IN';
我想,这将返回你正在寻找的东西。
我编辑了为inDad中的punchDirection添加检查。
您还可以更改选择部分以选择a。*,这将从记录中获取所有内容。
其他编辑:
上面的代码似乎已经解决了原来的问题但是当有人连续两次检查然后检出时真正的问题是什么。在MYSQL中,这是一个非常难以解决的问题,但在Postgres& Oracle,它相对简单,并且可以通过窗口函数来解决。我知道这并不能解决您的问题,但您可以在事后解决脚本问题。在postgres / oracle中,以下内容将找到您要查找的记录:
select * from
(select
a.punchId,
lag(b.punchDTC_LINK,1) over (
partition by a.employeeId
order by a.punchDATETIME
) prev_link,
a.punchDTC_LINK cur_link
from
timePunches a
left outer join timePunches b on
a.punchId = b.punchDTC_LINK)
where prev_link is null and cur_link is not null;
或类似的东西。我还没有测试过。
对于脚本,您可以使用以下查询:
select
a.punchId,
a.employeeID,
a.punchDATETIME,
a.punchDIRECTION,
b.punchDATETIME,
b.punchDIRECTION
from
timePunches a
left outer join timePunches b on
a.punchId = b.punchDTC_LINK
order by a.employeeID, a.punchDATETIME desc;
通过循环数据和/或编写脚本来循环数据并找到b.punchDIRECTION为空的位置并且它不是给定员工的第一条记录,您将很容易找到坏记录。
答案 3 :(得分:0)
由于您将其与最后一个IN匹配,因此搜索最后一个IN并将OUT附加到其中。但是我真的不明白,这就是为什么你必须在单个记录上匹配IN和out。
我必须每天开发一个计时系统才能获得IN和OUT。我们的计时系统具有针对每个冲头IN和OUT的单独记录。您可以搜索当前一天是连续两个IN还是连续两个OUT,然后是错误的,或者前一天连续两个IN或连续两个OUT或者不是以IN开头没有结束然后OUT就会出现误点
更新
我理解这一点,但为什么必须在输出线中存储IN打孔信息?打卡的时间总是按顺序排列。因此,如果时间以IN IN或IN OUT的顺序存储,这是最容易辨别的方式。
我建议将其存储为:
的示例IN 2012-01-08 08.00 AM
IN 2012-01-08 11.00 AM
OUT 2012-01-08 15.00 PM
您的检查是查看当天是否连续两个IN按时间顺序排列。 如果你想按照自己的方式进行操作,那么将所有单个INs与配对的IN匹配起来并获得不匹配的信息,所以基本上你只需要在右边的那个中用左手连接INs OUT然后左边的列表在匹配中具有空值将显示您的错误预测。