1

我有员工工作时间日志数据。现在我必须标记员工在连续工作日(周六/周日周末)为相同任务记录相同时间的所有记录。

让我用下面的例子解释我的问题

我有员工小时日志表说 EMP_HOUR_LOG:

ROW EMP_NO  TASK    DATE        HOURS   FLAG
1   1000    T1  2015-01-01  8   0
2   1000    T1  2015-01-02  8   0
3   1000    T1  2015-01-05  8   0
4   1000    T1  2015-01-06  2   0
5   1000    T2  2015-01-01  4   0
6   1000    T2  2015-01-02  3   0
7   1000    T3  2015-01-09  5   0
8   1000    T3  2015-01-12  5   0
9   1000    T3  2015-01-13  3   0
10  1001    T1  2015-01-14  3   0
11  1001    T1  2015-01-15  3   0

在上面的示例数据集中,我必须将第 1、2、3、10 和 11 行的 FLAG 更新为 1,因为这些记录是同一员工连续几天为同一任务输入的小时数相同的条目。

我已经使用游标实现了这一点,因为我想不出任何替代方法来逐条循环遍历数据记录。

请让我知道这里是否有人可以建议任何更好的方法来通过避免游标循环或一般循环来实现相同的方法。

谢谢

4

3 回答 3

0

我想我会稍微不同地解决这个问题。如果你有能力。这种计算更容易预先解决。因此,您可以在插入新记录时将其隔离,而不是查询整个问题集。基本上在您添加新记录并更新位于任一侧的任何记录时设置标志(日期方面),这具有始终使您的数据处于正确状态并且资源密集型较少的优势,因为您不需要考虑每条记录为了得出标志值。

于 2015-02-01T18:47:55.713 回答
0

可能第 7 行和第 8 行也应该有 flag = 1。这是查询,但我认为问题必须在插入期间处理:

update e set e.FLAG = 1 
from [dbo].[EMP_HOUR_LOG] e
where exists
(
    select * from [dbo].[EMP_HOUR_LOG] e1 
    where e1.[TASK] = e.[TASK] 
    and e1.[EMP_NO] = e.[EMP_NO]
    and e1.[HOURS] = e.[HOURS]
    and e1.[DATE] in 
        (
        --Next work day
        dateadd(dd, case when DATENAME(dw,e.[DATE]) = 'Friday' then 3 else 1 end, e.[DATE]), 
        --Previous work day
        dateadd(dd, case when DATENAME(dw,e.[DATE]) = 'Monday' then -3 else -1 end, e.[DATE])
        )
)
于 2015-02-01T21:38:22.153 回答
0

我不确定我是否理解正确:相同的员工,相同的任务,每天输入相同的小时数(连续 - 不包括周末)。

但是您描述的逻辑也会选择行:7 和 8

7   1000    T3  2015-01-09  5   0
8   1000    T3  2015-01-12  5   0

相同的员工1000相同的任务T3相同的小时数52015-01-09是星期五和2015-01-12星期一,所以天是连续的(周末除外)


考虑到我在这里得到的是 MS SQL 2008 实现:

WITH EHT AS (
SELECT [ROW]
      ,[EMP_NO]
      ,[TASK]
      ,[DATE]
      ,[HOURS]
      ,DATEPART(DW,[DATE]) AS DayWeek /* Sunday = 1 */
      ,ROW_NUMBER() OVER (PARTITION BY [EMP_NO],[TASK] ORDER BY [DATE]) AS DT_RNK
FROM [EMP_HOUR_LOG]
)

SELECT 
 A1.*
,A2.[DATE] AS Next_Date
,A3.[DATE] AS Previous_Date
,CASE /* for Next Date logic*/
     WHEN A2.DayWeek<>2 /*Tuesday to Friday*/
      AND DATEDIFF(DD, A1.[DATE], A2.[DATE]) = 1
     THEN 1
     WHEN  A2.DayWeek=2 /*Monday*/
      AND DATEDIFF(DD, A1.[DATE], A2.[DATE]) = 3 /* 3 days from Friday to Monday*/
     Then 1
     /* for Previous Date logic*/
     WHEN A2.[DATE] IS NULL 
      AND A3.DayWeek=6 /* Friday */
      AND DATEDIFF(DD, A3.[DATE], A1.[DATE]) = 3 /* 3 days from Friday to Monday*/
     THEN 1
     WHEN A2.[DATE] IS NULL 
      AND A3.DayWeek<>6 /* Mon to Thur */
      AND DATEDIFF(DD, A3.[DATE], A1.[DATE]) = 1 
     Then 1
     ELSE 0 END
 AS FLAG
FROM EHT AS A1
LEFT JOIN EHT AS A2
        ON (A1.[EMP_NO]=A2.[EMP_NO]
        AND A1.[TASK]=A2.[TASK]
        AND A1.[HOURS]=A2.[HOURS]
        AND A1.DT_RNK=A2.DT_RNK-1)
LEFT JOIN EHT AS A3
        ON (A1.[EMP_NO]=A3.[EMP_NO]
        AND A1.[TASK]=A3.[TASK]
        AND A1.[HOURS]=A3.[HOURS]
        AND A1.DT_RNK=A3.DT_RNK+1)

首先使用 Weekday 函数创建临时表 EHT 来识别一天是周六还是周日 (7,1)。从 1...n 添加订单号(Rwo_number 函数),在员工、任务和订购日期从最低到最高重置。

然后在第二步中将 EHT 表左连接到自身。使用 Emp、Task 和 hour 列(排除 emp、task 和 hours 不匹配的所有情况)+ 将第二个表向后移动 1 个 Order num ( A1.DT_RNK=A2.DT_RNK-1)。有了它,我就能够识别系列中的下一个数据。

但是,系列中的最后一个日期没有下一个日期,因为它是最后一个。我需要从头到尾识别系列。因此,我将再次加入表格,但这次,将表格向前移动 1 个订单号 ( A1.DT_RNK=A2.DT_RNK+1) 以识别系列中的上一个日期。

现在的逻辑只是计算日期和下一个日期或日期和上一个日期之间的天数,如果等于 1,那么它们是连续的。对于星期一日期,它必须是 3。同样,当考虑到意甲中没有下一个日期的最后一个条目时,如果是星期五,我们需要检查上一个日期,那么它也必须等于 3。

可能有更简单的解决方案。但这是有效的。仍然像上面提到的 Gordon Linoff 一样,您没有将第 7 行和第 8 行包含在 FLAG = 1 中。我的逻辑包括它们,因为它是从星期五到星期一的连续日期。也许您正在考虑其他一些假期。

结果详情: 在此处输入图像描述

于 2015-02-01T21:28:43.790 回答