将整个查询日期范围的存储桶中的持续时间分组,然后按日期显示

Group durations in buckets for entire query date range, then display by date

我有一组数据,按日期提供用户加班时间。

我需要以这种方式进一步拆分:

因为数据需要按天显示,我很难实现。

我正在处理的数据如下所示:

SELECT 
    USERNAME,
    DATE,
    SUM (DATEDIFF(SECOND, STARTTIME, ENDTIME) / 3600.0) AS OT_DURATION
FROM EVENTS
WHERE EVENT_TYPE = 'OVERTIME'
AND DATE BETWEEN '2021-01-25' AND '2021-01-31'
;

当前输出:

| USERNAME | DATE       | OT_DURATION |
|----------|------------|-------------|
| bob      | 2021-01-25 | 2.0         |
| bob      | 2021-01-26 | 2.0         |
| bob      | 2021-01-27 | 3.0         |
| bob      | 2021-01-28 | 2.0         |
| bob      | 2021-01-29 | 0.0         |

期望的输出:

| USERNAME | DATE       | OT_FIRST-5_HRS | OT_AFTER_5_HRS |
|----------|------------|---------------------------------|
| bob      | 2021-01-25 | 2.0            | 0.0            |
| bob      | 2021-01-26 | 2.0            | 0.0            |
| bob      | 2021-01-27 | 1.0            | 2.0            |
| bob      | 2021-01-28 | 0.0            | 2.0            |
| bob      | 2021-01-29 | 0.0            | 0.0            |

澄清一下,OT_FIRST_5_HRS 是整个查询期间的前 5 小时,而不仅仅是当天。同样适用于 OT_AFTER_5_HRS.

1 周只是一个示例,但理想情况下,该解决方案适用于任何日期范围。

请注意,我正在使用 SQL Server 2016。

如有任何帮助,我们将不胜感激。

您可以使用 window 函数。为此,子查询使逻辑更容易理解:

SELECT USERNAME, DATE, OT_DURATION,
       (CASE WHEN RUNNING_OT < 5 THEN OT_DURATION
             WHEN RUNNING_OT - OT_DURATION < 5 THEN 5 - (RUNNING_OT - OT_DURATION)
             ELSE 0
        END) as ot_first,
       (CASE WHEN RUNNING_OT - OT_DURATION >= 5 THEN OT_DURATION
             WHEN RUNNING_OT - OT_DURATION < 5 THEN RUNNING_OT - 5
             ELSE 0
        END) as ot_first
FROM (SELECT USERNAME, DATE,
             SUM(DATEDIFF(SECOND, STARTTIME, ENDTIME) / 3600.0) AS OT_DURATION,
             SUM(SUM(DATEDIFF(SECOND, STARTTIME, ENDTIME) / 3600.0)) OVER (PARTITION BY USERNAME ORDER BY DATE) as RUNNING_OT
      WHERE EVENT_TYPE = 'OVERTIME' AND
            DATE BETWEEN '2021-01-25' AND '2021-01-31'
      FROM EVENTS
     ) e;

注意:由于 WHERE 条款,您的数据是一周的。如果您想要多个星期,那么您需要在 PARTITION BY 子句中包含“周”逻辑。我没有这样做,因为周的定义可能很挑剔,而且与您提出的问题并没有真正的关系。