将整个查询日期范围的存储桶中的持续时间分组,然后按日期显示
Group durations in buckets for entire query date range, then display by date
我有一组数据,按日期提供用户加班时间。
我需要以这种方式进一步拆分:
- 在 1 列的整个日期范围内加班最多 5 小时
- 另一列中整个日期范围的最初 5 小时后的加班
因为数据需要按天显示,我很难实现。
我正在处理的数据如下所示:
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
子句中包含“周”逻辑。我没有这样做,因为周的定义可能很挑剔,而且与您提出的问题并没有真正的关系。
我有一组数据,按日期提供用户加班时间。
我需要以这种方式进一步拆分:
- 在 1 列的整个日期范围内加班最多 5 小时
- 另一列中整个日期范围的最初 5 小时后的加班
因为数据需要按天显示,我很难实现。
我正在处理的数据如下所示:
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
子句中包含“周”逻辑。我没有这样做,因为周的定义可能很挑剔,而且与您提出的问题并没有真正的关系。