【问题标题】:SQL finding total flagged hours within first 8 hours workedSQL 查找前 8 小时内工作的总标记小时数
【发布时间】:2019-11-26 06:06:20
【问题描述】:

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

示例

  • 凌晨 2 点 - 凌晨 4 点(2 小时)- 正常班次
  • 上午 5 点 - 上午 9 点(4 小时)- 标记班次
  • 上午 10 点 - 下午 3 点(5 小时)- 标记班次

符合条件的总时间为 4 小时(上午 5 点至上午 9 点)+ 2 小时(上午 10 点至下午 12 点)

源表格式

个人ID |工作日期 |开始时间 |结束时间 |工作时间(预先计算)|换档

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             |
+----------+------------+---------------------+---------------------+------------------------------+-----------+---------------+

【问题讨论】:

  • SO 不是代码编写服务,您需要尝试在卡住时提出问题。
  • 感谢您的回复。我尝试了几种方法,但找不到正确的方法。它的解决方案似乎是在将光标编码为循环并返回符合条件的小时数(可能性能也很慢)或可以计算窗口限制的查询之间,这样我就可以在第一个班次开始时间和限制时间之间进行总计。在我的示例中,这将是凌晨 2 点到下午 12 点之间的时间。我找不到计算该限制的方法。
  • 展示你的尝试——当然它不能正常工作,这就是你寻求帮助的原因:)
  • 我同意 Dale 的观点,但在这种情况下,我觉得我尝试使用窗口或运行总计的尝试可能会产生误导,并且与实际解决方案无关。就像在寻找苹果时提供香蕉一样。下次我会更好地记录我的研究。

标签: sql sql-server ranking row-number windowing


【解决方案1】:

这是我对要求的理解:

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

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

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

代码如下:

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

还有小提琴:http://sqlfiddle.com/#!18/7a8dd/12

【讨论】:

  • 谢谢,在服务器 2016 上测试时,它完全符合我的要求。但我忘了提到我需要 2008 兼容性,用 Row_Number + 1 上的 Self Join 替换 lag 函数让我找到了相同的结果。 This answer 在另一个线程上有帮助。
猜你喜欢
  • 2020-01-04
  • 2020-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
  • 2016-08-02
相关资源
最近更新 更多