查找时间跨越午夜边界的每组的第一天
Posted
技术标签:
【中文标题】查找时间跨越午夜边界的每组的第一天【英文标题】:Find first day per group where time spans midnight boundaries 【发布时间】:2018-11-15 10:52:51 【问题描述】:我有一张表格,可以计算一个人的工作时间。我们有一个夜间团队,可以在下午 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
关于如何做到这一点的任何想法?感谢任何帮助
杰斯
【问题讨论】:
您将需要使用窗口函数。您是否有唯一标识其中一名员工的字段?像 UserId 一样? 是的,我们有一个用户 ID 和一个用户名字段 我们可以假设一个人的停留时间永远不会超过 23 小时吗? 这是正确的 【参考方案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
【讨论】:
【参考方案2】:当我有一个工作示例时,我会更新,但请尝试:
SELECT
MIN(WorkDate) OVER (PARTITION BY UserId ORDER BY WorkHour) [ReportingDate]
FROM <YourTable>
WHERE WorkDate >= CAST(DATEADD(DAY, -1, GETDATE()) AS DATE)
【讨论】:
这将是一份历史报告,因此有时可能会运行过去一段时间,即上周。 是否有班次 ID 或可识别班次的内容?【参考方案3】:这是“gaps-and-islands”的变体。您可以通过减去枚举序列来识别相邻的时间。之后,您只需要对组进行最大值即可。
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
【讨论】:
datediff(day,
必须是 dateadd(hour,
。以上是关于查找时间跨越午夜边界的每组的第一天的主要内容,如果未能解决你的问题,请参考以下文章