列表工时包含多个班次和日期

时间:2017-12-06 17:52:48

标签: tsql

关于如何在SQL 2012中处理一些员工计时查询,我有几个问题......我上周曾问过另一个关于确定轮班之间时间的问题,我能够得到很好的回应。

我们从销售点软件提供商处获取数据,因此我们无法更改数据格式。

工作日基于DateOfBusiness,这是从下一个日历日凌晨5点到凌晨4点59分,所以它跨越了午夜。位置结束日过程略微偏移以控制平衡负载,有些是早上5:05而不是凌晨5:00。当“结束日”过程运行时,它会将所有人计时,然后在过程完成时将其计时。      - 员工需要30分钟的休息时间,因此这些员工每天有2个或更多的记录。不确定原因,但是一些员工在一天内有超过3条记录(EmployeeShiftNumber)。      - 班次偶尔会越过DateOfBusiness。在晚上11点 - 早上7点出发

我需要报告初始InTime和Final OutTime列表以及工作分钟数。我必须将这些与持有员工日程表的表进行比较。此报告不是用于工资核算,而是用于与计划班次进行比较。

我已经包含了一些按员工和按日分组的样本数据,以及我希望看到的右侧评论的值。我还需要查看班次中的工作分钟数。

--drop table #Shift

CREATE TABLE #Shift(
    FKEmployeeNumber int,
    DateOfBusiness datetime,
    FKStoreId int,
    EmployeeShiftNumber int,
    FKJobCodeId int,
    InHour int,
    InMinute int,
    OutHour int,
    OutMinute int)

insert into #Shift ( FKEmployeeNumber, DateOfBusiness, FKStoreId, EmployeeShiftNumber, FKJobCodeId, InHour, InMinute,OutHour,OutMinute)
values
(23761, '11/30/2017', 3013, 0, 1, 17, 39, 21, 30),
(23761, '11/30/2017', 3013, 1, 1, 21, 30, 2, 39),   -- 5:39PM  2:39AM

(23770, '11/30/2017', 3013, 0, 200, 7, 19, 16, 25), -- 7:19AM  4:25PM

(23938, '11/30/2017', 3013, 0, 1, 16, 4, 1, 26),    -- 4:04AM  1:26AM

(24006, '11/30/2017', 3013, 0, 1, 7, 30, 18, 36),
(24006, '11/30/2017', 3013, 1, 1, 18, 36, 18, 40),  -- 7:30AM  6:40PM

(24018, '11/30/2017', 3013, 0, 2, 8, 52, 17, 0),    -- 8:52M  4:00PM

(25176, '11/30/2017', 3013, 0, 200, 15, 59, 20, 1), -- 3:59PM  8:01PM

(25176, '11/30/2017', 3013, 1, 200, 20, 30, 0, 05), -- 8:30PM  12:05AM

(25180, '11/30/2017', 3013, 0, 1, 21, 0, 5, 0),     -- 9:00PM  5:00AM

(25187, '11/30/2017', 3013, 0, 1, 10, 0, 16, 6),    -- 10:00AM  4:06PM

(35189, '11/30/2017', 3013, 0, 1, 16, 58, 2, 4),    -- 4:58PM  2:04AM

(25147, '12/04/2017', 3106, 0, 1, 6, 58, 15, 2),
(25147, '12/04/2017', 3106, 1, 1, 15, 3, 15, 3),    -- 6:58AM  3:03PM

(26291, '12/01/2017', 3118, 1, 200, 23, 15, 5, 5),
(26291, '12/02/2017', 3118, 0, 200, 5, 6, 7, 22),   -- 11:15PM  7:22AM

(26291, '12/03/2017', 3118, 0, 200, 7, 30, 15, 38), -- 7:30AM  3:38PM

(26291, '12/04/2017', 3118, 0, 200, 23, 15, 5, 5),
(26291, '12/05/2017', 3118, 0, 200, 5, 6, 7, 12),   -- 11:15PM  7:12AM

(26291, '12/05/2017', 3118, 1, 200, 23, 15, 5, 5),
(26291, '12/06/2017', 3118, 0, 200, 15, 14, 7, 5)   -- 11:15PM  7:05AM
--Select * from #Shift

SELECT fkstoreid, FKEmployeeNumber AS EmpID, DateOfBusiness AS Date, 
    RIGHT(CONVERT(varchar(30), DATEADD(MINUTE, InTime_Mins, 0), 100), 7) AS InTime,
    RIGHT(CONVERT(varchar(30), DATEADD(MINUTE, OutTime_Mins, 0), 100), 7) AS OutTime,
    MinsWorked
FROM (
    select sh.FKStoreId, sh.FKEmployeeNumber, sh.DateOfBusiness, 
        MIN(sh.InHour*60+InMinute) AS InTime_Mins,
        MAX(sh.OutHour*60+OutMinute) AS OutTime_Mins,
        SUM(((sh.outhour+case when sh.OutHour < sh.InHour then 24 else 0 end)*60 + sh.outminute) -
             (sh.inhour*60 + sh.inminute)) AS MinsWorked
    from #shift sh
    group by sh.FKStoreId,sh.FKEmployeeNumber, sh.DateOfBusiness
) AS derived
order by FKEmployeeNumber, DateOfBusiness

1 个答案:

答案 0 :(得分:0)

我已经写了一个如何做到这一点的样本。

简要总结一下,我执行了以下步骤:

  1. 标记应与下一个或上一个记录分组的记录,因为它们是同一班次的一部分。
  2. 查找每个班次的开始和结束
  3. 加入每个班次内的员工的所有记录
  4. 将每位员工的每个班次的结果集分组,并通过总结班次中每个记录的签入和结帐之间的分钟来计算工作分钟数。
  5. 示例查询:

    WITH ShiftParts AS (
        SELECT
            FKEmployeeNumber,
            DATEADD(MINUTE, InMinute, DATEADD(HOUR, InHour, DateOfBusiness)) CheckIn, --Datetime of the checkin
            DATEADD(DAY, CASE WHEN OutHour < InHour THEN 1 ELSE 0 END,
                DATEADD(MINUTE, OutMinute, DATEADD(HOUR, OutHour, DateOfBusiness))) CheckOut --Datetime of the checkout (add one day if we crossed midnight).
        FROM #Shift
    ), 
    GroupInfo AS (
        SELECT 
            *,
            CASE 
                WHEN DATEDIFF(MINUTE, LAG(CheckOut, 1, NULL) OVER (PARTITION BY FKEmployeeNumber ORDER BY CheckOut), CheckIn) <= 120 
                THEN 1 ELSE 0 END AS GroupWithPrevious, --Determine whether we want to group this record with the previous
            CASE 
                WHEN DATEDIFF(MINUTE, CheckOut, LEAD(CheckIn, 1, NULL) OVER (PARTITION BY FKEmployeeNumber ORDER BY CheckOut)) <= 120 
                THEN 1 ELSE 0 END AS GroupWithNext --Determine whether we want to group this record with the next
        FROM ShiftParts
    ), ShiftStartAndEnd AS (
        SELECT
            *,
            CASE WHEN GroupWithNext = 1 THEN LEAD(CheckOut, 1, NULL) OVER (PARTITION BY FKEmployeeNumber ORDER BY CheckOut) ELSE CheckOut END AS FinalCheckOut
        FROM GroupInfo 
        WHERE GroupWithPrevious = 0 OR GroupWithNext = 0 --Only pick beginning and end of a shift
    )
    SELECT 
        sse.FKEmployeeNumber, 
        sse.CheckIn, 
        sse.FinalCheckOut,
        SUM(DATEDIFF(MINUTE,sp.CheckIn,sp.CheckOut)) AS MinutesWorked
    FROM ShiftStartAndEnd sse
        LEFT OUTER JOIN ShiftParts sp ON sp.FKEmployeeNumber = sse.FKEmployeeNumber AND sp.CheckIn >= sse.CheckIn AND sp.CheckOut <= sse.FinalCheckOut
    WHERE sse.GroupWithPrevious = 0
    GROUP BY sse.FKEmployeeNumber, sse.CheckIn, sse.FinalCheckOut
    

    注意:我认为样本数据中的最后两个记录不应该分组

    (26291, '12/05/2017', 3118, 1, 200, 23, 15, 5, 5),
    (26291, '12/06/2017', 3118, 0, 200, 15, 14, 7, 5)   -- 11:15PM  7:05AM
    

    应该是:

    (26291, '12/05/2017', 3118, 1, 200, 23, 15, 5, 5),  -- 11:19PM  5:05AM
    (26291, '12/06/2017', 3118, 0, 200, 15, 14, 7, 5)   -- 3:14PM  7:05AM