SQL 查找前 8 小时内标记的总时数

SQL finding total flagged hours within first 8 hours worked

我的目标是找到一天中每个人的轮班工作总时数或每人轮班的分数,这些小时数被标记为一个值,并且在任何一天的前 8 个小时内工作,不包括休息时间。然后显示标记的班次以及符合条件的总价值。

例子

符合条件的总计 4 小时(上午 5 点 - 上午 9 点)+ 2 小时(上午 10 点 - 中午 12 点)

来源Table格式

人号 |工作日期 |开始时间 |结束时间 |工作小时数(预先计算)|转换类型

DECLARE @Table TABLE
(
    PersonID INT
    , WorkDate DATETIME
    , StartTime DATETIME
    , FinishTime DATETIME
    , HoursWorked DECIMAL(4, 2)
    , ShiftType VARCHAR(50)

);

INSERT INTO @Table VALUES (100,'2019-11-26','1900-01-01T02:00:00', '1900-01-01T04:00:00',2,'Normal')
INSERT INTO @Table VALUES (100,'2019-11-26','1900-01-01T05:00:00', '1900-01-01T09:00:00',4,'Tagged')
INSERT INTO @Table VALUES (100,'2019-11-26','1900-01-01T10:00:00', '1900-01-01T15:00:00',5,'Tagged')

结果集

+----------+------------+---------------------+---------------------+------------------------------+-----------+---------------+
| PersonID | WorkDate   | StartTime           | FinishTime          | HoursWorked (pre calculated) | ShiftType | EligibleHours |
+----------+------------+---------------------+---------------------+------------------------------+-----------+---------------+
| 100      | 2019-11-26 | 1900-01-01T05:00:00 | 1900-01-01T09:00:00 | 4                            | Tagged    | 4             |
+----------+------------+---------------------+---------------------+------------------------------+-----------+---------------+
| 100      | 2019-11-26 | 1900-01-01T10:00:00 | 1900-01-01T15:00:00 | 5                            | Tagged    | 2             |
+----------+------------+---------------------+---------------------+------------------------------+-----------+---------------+

以下是我对要求的理解:

  • 收集每位用户每天前 8 小时完成的工作
  • 如果班次在 8 小时之前开始并在 8 小时之后结束,则应标记用户到达 8 小时之前发生的小时数
  • 过滤掉所有未标记的班次
  • 过滤掉所有不符合条件的班次

为了解决我使用了两个窗口函数:

  • sum(TotalHours) over (...) 以确定当前班次和之前所有班次的工作小时数的累计总和
  • (8 - lag(CumulativeWork, 1, 0)) over (...) 以确定进入当前班次还剩多少资格。

代码如下:

select 
  PersonID,
  WorkDate,
  StartTime,
  FinishTime,
  HoursWorked,
  ShiftType,
  case 
    when RemainingWork <= HoursWorked then RemainingWork
    when RemainingWork > HoursWorked then HoursWorked 
    else 0 end as EligibleWork
from 
(
  select 
  -- Calculate how much eligible work can happen in a given shift by 
  -- subtracting the amount of work done in previous shifts from 8
  8 - lag (CumulativeWork, 1, 0) over (Partition by PersonID, WorkDate order by StartTime) as RemainingWork
  , *
  from (
    select 
    -- Create a cumulative sum of the hours worked
    sum(HoursWorked) over (Partition by PersonID, WorkDate order by StartTime) as CumulativeWork
    , *
    from ShiftTable
  ) a
) b
where shiftType = 'Tagged' and remainingWork > 0

和fiddle:http://sqlfiddle.com/#!18/7a8dd/12