SQL - 对员工入口时间进行分类

时间:2014-04-27 16:59:06

标签: c# sql sql-server-2012

我有一个SQL表,我将每个员工存储在IN和OUT时间戳中。

有些员工不止一次打卡(因为他们没有听到卡被读取),其他员工因某种原因打卡(也许他们遇到了朋友和他们会等待几分钟,然后再次打开进入旋转栅门。

示例SQL表数据如下所示(仅限3名员工):

enter image description here

现在,我想每次分类以了解时间戳是否正确等等。

例如:

enter image description here

在你看到 EMP_01 (黄色记录)时,LAST_LEAVE技术上是00:38:21,但很明显,员工打了两次就是为什么真正的LAST_LEAVE是00:38:16。

但是,EMP_04有一些其他问题,如果你看到最后4个记录,他连续3个IN,但那些不是因为他没有听到传感器的嘟嘟声,那是因为他从其他门离开没有打击谁知道什么时候,但我们知道他再次进入1小时,依此类推。

那么,关于如何处理这个的任何建议?以及如何分配我的“状态”标志?

更新

如果EMP_04有3个相同类型的连续时间戳(IN或OUT),例如:

  • 9:04:27 am(IN)
  • 上午9:04:35(IN)
  • 上午9:04:40(IN)

我的容忍度在120秒之间,所以第一次9:04:27就可以,但接下来的2个连续时间戳应该是不活动的,因为我的容差是120秒。

但是,例如,如果EMP_04具有以下连续时间戳:

  • 9:04:27 am(IN)
  • 上午9:04:35(IN)
  • 上午9:08:10(IN)

然后标记为非活动的唯一时间将是上午9:04:35。因为在9:04.35和9:08:10之间大于2分钟。

3 个答案:

答案 0 :(得分:2)

首先,承认@RamRS将努力工作放入触发器中,这是一个经过测试并应该开始使用的工作。显然,对于极端情况需要一些强大的测试:

CREATE TRIGGER TS_FindDups ON dbo.TS FOR INSERT
AS
BEGIN

;WITH DupRecords
AS
(
        SELECT i.EmployeeId, i.[TimeStamp]
          FROM inserted i
    INNER JOIN dbo.TS SRC ON i.EmployeeId = SRC.EmployeeId AND i.EntranceType = SRC.EntranceType
         WHERE SRC.[Status] != 'Inactive'
               /* same day (nice...thanks to RamRS) */
               AND CAST(i.[TimeStamp] AS date) =  CAST(SRC.[TimeStamp] AS date)
               /* only checking newer timestamps (also need this so DATEDIFF <= 2 works correctly) */
               AND i.[TimeStamp] > SRC.[TimeStamp]
               /* newer timestamps are less than two minutes for same Employee, same day, same EntranceType */
               AND DATEDIFF(MINUTE, SRC.[TimeStamp], i.[TimeStamp]) <= 2
)

      UPDATE dbo.TS
         SET [Status] = 'Inactive'
        FROM dbo.TS SRC
  INNER JOIN DupRecords ON SRC.EmployeeId = DupRecords.EmployeeId AND SRC.[TimeStamp] = DupRecords.[TimeStamp]

END

答案 1 :(得分:1)

就像@mdisibio所述,我们可以使用触发器来添加值&#34; INACTIVE&#34;在插入行时复制行。

这个触发器的草图将是:

CREATE TRIGGER trg_FindDups ON tbl_TimeStamp FOR INSERT
AS
BEGIN
    DECLARE @CurrentMaxSwipeTime DATETIME
    DECLARE @SwipeType
    SELECT @SwipeType = EntranceType FROM INSERTED

    IF (@SwipeType = 'O')
    BEGIN
        /* Employee is swiping OUT */
        SELECT @CurrentMaxSwipeTime = MAX(T.TimeStamp) FROM tbl_TimeStamp T 
        WHERE T.EmployeeID = (SELECT EmployeeID FROM INSERTED) /* Same employee */
        AND DATE(T.TimeStamp) = CAST(GETDATE() AS DATE) /* Same date */
        AND DATEDIFF(minute,T.TimeStamp,GETDATE())<2 /* Within 2 minutes */
        AND T.Status <> 'INACTIVE' /* of an active swipe */
        AND T.EntraceType = 'O' /* Swiping out */
        AND T.TimeStamp <> (SELECT TimeStamp FROM INSERTED) /* not the row we just inserted, H/T @mdisibio
        IF @CurrentMaxSwipeTime IS NOT NULL
            /* SET Status to INACTIVE */
            UPDATE tbl_TimeStamp SET Status='INACTIVE' WHERE EmployeeID=(SELECT EmployeeID FROM INSERTED) AND TimeStamp=(SELECT TimeStamp FROM INSERTED)
    END

    ELSE
    BEGIN
        /* Employee is swiping in */
        SELECT @CurrentMaxSwipeTime = MIN(T.TimeStamp) FROM tbl_TimeStamp T 
        WHERE T.EmployeeID = (SELECT EmployeeID FROM INSERTED) /* Same employee */
        AND DATE(T.TimeStamp) = CAST(GETDATE() AS DATE) /* Same date */
        AND DATEDIFF(minute,T.TimeStamp,GETDATE())<2 /* Within 2 minutes */
        AND T.Status <> 'INACTIVE' /* of an active swipe */
        AND T.EntraceType = 'I' /* Swiping in */
        AND T.TimeStamp <> (SELECT TimeStamp FROM INSERTED) /* not the row we just inserted, H/T @mdisibio
        IF @CurrentMaxSwipeTime IS NOT NULL
            /* SET Status to INACTIVE */
            UPDATE tbl_TimeStamp SET Status='INACTIVE' WHERE EmployeeID=(SELECT EmployeeID FROM INSERTED) AND TimeStamp=(SELECT TimeStamp FROM INSERTED)
    END
END

自从我使用SQL Server以来已经有几年了,但我真的希望代码中没有错误。

-
干杯,
拉姆

答案 2 :(得分:0)

让我快速总结一下你的问题并逐一介绍:

  1. 错误地滑动两次时复制OUT记录。如何设置状态?
  2. 重复IN记录,因为并非所有门都刷过,也没有记录相应的OUT记录。再次如何设置状态?
  3. 假设:

    1. 如果人们错误地多次扫描,您可以获得重复的IN和OUT记录。
    2. 你不会在目前没有它们的门上安装卡片扫描仪......
    3. 这是一个不完善的系统,因此您不会删除\忽略不同情况下的任何扫描。
    4. 所以... 在两者之间重复记录几分钟。为了确定用户的状态,您必须查看他们的历史记录。我相信你有一个几分钟的容差的想法是一个很好的,虽然这应该在IN和OUT扫描检查。对于IN,你应该总是拿第一个。对于OUT,你应该总是拿最后一个。

      我想的是,每当您为特定日期插入/更新/删除特定员工的时间戳记录时,您都会重新计算当天的所有状态。这样,如果有重复扫描,您就不必担心在不同的行上向后和向前移动状态。

      您必须重新计算以下状态:

      1. FIRST_ENTRANCE - 特定日期入口类型I上员工的第一个时间戳行
      2. LAST_LEAVE - 具有特定入口类型O的员工的上次时间戳行 所有员工的一天。检查当天所有其他员工在设置此项之前的同一天没有这个。
      3. FIRST_IN - 具有特定入口类型I的员工的第一个时间戳行 所有员工的一天。检查当天所有其他员工在设置此项之前的同一天没有这个。