如何对从日期时间到日期时间的某些内容进行分组以获得该时间的空闲时间?

问题描述 投票:0回答:2

如何根据此原始数据获得预期输出 - 空闲时间?

原始数据

时间 超时
2024-09-01 10:00:00 2024-09-01 11:00:00
2024-09-01 10:00:00 2024-09-01 12:00:00
2024-09-01 10:20:00 2024-09-01 13:00:00
2024-09-01 14:00:00 2024-09-01 15:00:00
2024-09-01 15:30:00 2024-09-01 16:00:00

预期产量

时间 超时 持续时间 空闲时间
2024-09-01 10:00:00 2024-09-01 11:00:00 60分钟 0分钟
2024-09-01 10:00:00 2024-09-01 12:00:00 120分钟 0分钟
2024-09-01 10:20:00 2024-09-01 13:00:00 160分钟 0分钟
2024-09-01 14:00:00 2024-09-01 15:00:00 120分钟 60分钟
2024-09-01 15:30:00 2024-09-01 16:00:00 30分钟 30分钟

我达到了持续时间,但在空闲时间中挣扎。

这是我写的查询:

SELECT
    TimeIn, TimeOut, 
    DATEDIFF(MINUTE, Timein, Timeout) AS duration
FROM
    [test_idletime]
sql-server
2个回答
1
投票

对于重叠的时间范围,您可能会遇到一些奇怪的重叠场景,其中最后一个

TimeOut
不是来自紧邻的前一行(按
TimeIn
排序)。考虑时间范围:
09:00-10:30, 09:15-10:15, 09:30-10:00, 11:00-12:00
。最后一行计算出的
IdleTime
应该是30分钟,而不是60分钟。

要处理此问题,您需要计算当前的

TimeIn
与之前的
MAX(TimeOut)
TimeIn
的 < current
TimeIn
并进行比较。这可以使用适当约束的窗口函数来计算嵌套查询或CTE中的运行
MAX(TimeOut)
,并在外部/最终查询中计算
IdleTime
来完成。

计算出来的

SELECT
    TimeIn, TimeOut, MaxPriorTimeOut,
    DATEDIFF(MINUTE, TimeIn, TimeOut) as Duration,
    GREATEST(0, DATEDIFF(MINUTE, MaxPriorTimeOut, TimeIn)) as IdleTime
FROM (
    SELECT
        *,
        MAX(TimeOut) OVER(
               ORDER BY TimeIn
               ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            )AS MaxPriorTimeOut
    FROM Data
) T
ORDER BY TimeIn

GREATEST()
函数在 SQL Server 2022 及更高版本中可用。对于早期版本,您可以使用
CASE
表达式来获得相同的结果。

    CASE WHEN MaxPriorTimeOut < TimeIn
        THEN DATEDIFF(MINUTE, MaxPriorTimeOut, TimeIn)
        ELSE 0 END as IdleTime

结果(带有一些额外的测试数据):

时间 超时 最大优先超时 持续时间 空闲时间
2024-09-01 10:00 2024-09-01 11:00 60 0
2024-09-01 10:00 2024-09-01 12:00 2024-09-01 11:00 120 0
2024-09-01 10:20 2024-09-01 13:00 2024-09-01 12:00 160 0
2024-09-01 14:00 2024-09-01 15:00 2024-09-01 13:00 60 60
2024-09-01 15:30 2024-09-01 16:00 2024-09-01 15:00 30 30
2024-09-02 09:00 2024-09-02 10:30 2024-09-01 16:00 90 1020
2024-09-02 09:15 2024-09-02 10:15 2024-09-02 10:30 60 0
2024-09-02 09:30 2024-09-02 10:00 2024-09-02 10:30 30 0
2024-09-02 11:00 2024-09-02 12:00 2024-09-02 10:30 60 30
2024-09-03 08:00 2024-09-03 09:00 2024-09-02 12:00 60 1200
2024-09-03 10:00 2024-09-03 12:00 2024-09-03 09:00 120 60
2024-09-03 10:30 2024-09-03 11:30 2024-09-03 12:00 60 0

请参阅 this db<>fiddle 进行演示。


0
投票

嗯,我发现了一些东西,但可能可以更即兴创作,任何新的想法都是受欢迎的:

enter image description here

SELECT TimeIn,TimeOut, 
  DATEDIFF(MINUTE, Timein, Timeout)  as duration,
  case when DATEDIFF(MINUTE, TimeIn, lag(TimeOut) OVER (ORDER BY timeout asc))  < 0 
    then SUBSTRING(Convert(varchar, DATEDIFF(MINUTE, TimeIn
                    , lag(TimeOut) OVER (ORDER BY timeout))) 
     , 2, 100) -- value came as - to remove - added substing
  else '0' end as idletime
FROM [test_idletime]
© www.soinside.com 2019 - 2024. All rights reserved.