查找时间跨午夜界限的每个小组的第一天

时间:2018-11-15 10:52:52

标签: sql sql-server datetime sql-server-2012 gaps-and-islands

我有一张表格,可以计算一个人的工作时间。我们有一个夜间团队,该团队可以在下午4点之后随时登录,并在第二天早上8点之前注销。该表如下所示。

 Workdate      WorkHour
2018-11-13         20       -- this was the hour they logged on
2018-11-13         21
2018-11-13         22
2018-11-13         23
2018-11-14         0
2018-11-14         1
2018-11-14         2
2018-11-14         3
2018-11-14         4
2018-11-14         5        -- this was the hour they logged off

出于报告的目的,我们仅要将这些工作时间与他们首次登录的日期(在此示例中为2018年11月13日)相关联。我的理想输出如下所示。

Workdate      WorkHour    ReportingDate
2018-11-13         20      2018-11-13 
2018-11-13         21      2018-11-13 
2018-11-13         22      2018-11-13 
2018-11-13         23      2018-11-13 
2018-11-14         0       2018-11-13 
2018-11-14         1       2018-11-13 
2018-11-14         2       2018-11-13 
2018-11-14         3       2018-11-13 
2018-11-14         4       2018-11-13 
2018-11-14         5       2018-11-13 

关于如何执行此操作的任何想法?感谢任何帮助

杰西

3 个答案:

答案 0 :(得分:1)

您可以将其视为间隔和孤岛问题,其中连续时间代表孤岛。您需要找到所有岛屿并找到每个岛屿的最短日期:

DECLARE @T TABLE (userid INT, workdate DATE, workhour INT);
INSERT INTO @t VALUES
(1, '2018-11-13', 20),
(1, '2018-11-13', 21),
(1, '2018-11-13', 22),
(1, '2018-11-13', 23),
(1, '2018-11-14',  0),
(1, '2018-11-14',  1),
(1, '2018-11-14',  2),
(1, '2018-11-14',  3),
(1, '2018-11-14',  4),
(1, '2018-11-14',  5),
(1, '2018-11-20', 6);

WITH cte1 AS (
    SELECT userid, workdate, workhour
         , DATEADD(HOUR, workhour, CAST(workdate AS DATETIME)) AS workdatetime
    FROM @t
), cte2 AS (
    SELECT userid, workdate, workhour
         , CASE WHEN DATEDIFF(HOUR, LAG(workdatetime) OVER (PARTITION BY userid ORDER BY workdate, workhour), workdatetime) = 1 THEN 0 ELSE 1 END AS chg
    FROM cte1
), cte3 AS (
    SELECT userid, workdate, workhour
         , SUM(chg) OVER (PARTITION BY userid ORDER BY workdate, workhour) AS grp
    FROM cte2
)
SELECT userid, workdate, workhour, MIN(workdate) OVER (PARTITION BY userid, grp) AS ReportingDate
FROM cte3
ORDER BY userid, workdate, workhour

答案 1 :(得分:0)

当我有一个可行的示例时,我会进行更新,但是请尝试:

SELECT
MIN(WorkDate) OVER (PARTITION BY UserId ORDER BY WorkHour) [ReportingDate]
FROM <YourTable>
WHERE WorkDate >= CAST(DATEADD(DAY, -1, GETDATE()) AS DATE)

答案 2 :(得分:0)

这是“空白和孤岛”的变体。您可以通过减去枚举序列来确定相邻的小时数。之后,您只需要在组中使用最大值即可。

select t.*,
       min(workdate) over (partition by datediff(hour, - seqnum, workdatehour) as imputed_workdate
from (select t.*,
             dateadd(hour, workhour, workdate) as workdatehour,
             row_number() over (order by workdate, workhour) as seqnum
      from t
     ) t