根据开始和结束时间每小时拆分持续时间

use*_*190 5 sql-server-2008 sql-server

我有一个表,用于注册设备的状态。状态有开始时间和结束时间。但现在我想知道每个小时的状态是什么。如果从 15:20 到 17:10 的状态是“Operating”,我想看到它在一天的第 16 个小时运行 40 分钟,第 17 个小时运行 60 分钟,第 18 个小时运行 10 分钟当天。

这就是我现在所拥有的:

Shift_date 状态 Start_timestamp End_Timestamp
---------- --------- --------------- ---------------
5/20/2017 运营 5/20/2017 8:21 5/20/2017 10:40
5/21/2017 延迟 5/20/2017 10:40 5/20/2017 11:10
5/22/2017 运营 5/20/2017 11:10 5/20/2017 13:50

这就是我要的:

Shift_date 小时状态持续时间(分钟)
---------- ---- --------- ----------
5/20/2017 1 .. ..
2017 年 5 月 20 日 ..... ..
5/20/2017 9 运营 39
5/20/2017 10 运营 60
5/20/2017 11 运营 40
5/20/2017 11 延迟 20
5/20/2017 12 延迟 10
5/20/2017 12 运营 50
5/20/2017 13 运营 50
5/20/2017 13 .. ..
5/20/2017 14 .. ..
2017 年 5 月 20 日 ..... ..
5/20/2017 24 .. ..

Joe*_*ish 5

这里的基本思想是根据状态表覆盖的小时数为状态表中的每一行添加行。我通过加入数字表来做到这一点。从那里,您只需要考虑所有不同的情况,以找出与每个小时时段相关的状态分钟数。

数据准备:

CREATE TABLE #t (
Shift_date DATETIME NOT NULL,
[Status] VARCHAR(20) NOT NULL,
Start_timestamp DATETIME NOT NULL,
End_Timestamp DATETIME NOT NULL
);

INSERT INTO #t VALUES ('5/20/2017', 'Operating', '5/20/2017 8:21', '5/20/2017 10:40');
INSERT INTO #t VALUES ('5/20/2017', 'Delay', '5/20/2017 10:40', '5/20/2017 11:10');
INSERT INTO #t VALUES ('5/20/2017', 'Operating', '5/20/2017 11:10', '5/20/2017 13:50');
Run Code Online (Sandbox Code Playgroud)

一种应该在 2008 年工作的方法:

-- may need more rows here depending on how long the events can be
WITH numbers (n) AS ( 
    SELECT 0 
    UNION ALL SELECT 1 
    UNION ALL SELECT 2 
    UNION ALL SELECT 3 
    UNION ALL SELECT 4 
    UNION ALL SELECT 5
)
SELECT 
   t2.Shift_date
 , DATEPART(HOUR, start_final) AS [hour]
 , t2.[Status]
 , DATEDIFF(MINUTE, start_final, end_final) Duration
FROM
(
    SELECT Shift_date
    , [Status]
    , Start_timestamp
    , End_Timestamp
    , CASE WHEN t.Start_timestamp > n.start_from_numbers THEN t.Start_timestamp ELSE n.start_from_numbers END start_final
    , CASE WHEN t.End_timestamp > n.end_from_numbers THEN n.end_from_numbers ELSE t.End_timestamp END end_final
    FROM #t t
    CROSS APPLY
    (
        SELECT dateadd(hour, n.n + datediff(hour, 0, t.Start_timestamp), 0) start_from_numbers
        , dateadd(hour, 1 + n.n + datediff(hour, 0, t.Start_timestamp), 0) end_from_numbers
        FROM numbers n WHERE DATEDIFF(HOUR, t.Start_timestamp, t.End_Timestamp) >= n.n
    ) n
) t2
ORDER BY start_final;
Run Code Online (Sandbox Code Playgroud)

我的结果(看起来您的样本数据有一些问题):

?????????????????????????????????????????????????????????
?       Shift_date        ? hour ?  Status   ? Duration ?
?????????????????????????????????????????????????????????
? 2017-05-20 00:00:00.000 ?    8 ? Operating ?       39 ?
? 2017-05-20 00:00:00.000 ?    9 ? Operating ?       60 ?
? 2017-05-20 00:00:00.000 ?   10 ? Operating ?       40 ?
? 2017-05-20 00:00:00.000 ?   10 ? Delay     ?       20 ?
? 2017-05-20 00:00:00.000 ?   11 ? Delay     ?       10 ?
? 2017-05-20 00:00:00.000 ?   11 ? Operating ?       50 ?
? 2017-05-20 00:00:00.000 ?   12 ? Operating ?       60 ?
? 2017-05-20 00:00:00.000 ?   13 ? Operating ?       50 ?
?????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)


Sql*_*ide 0

您可能希望将其放在另一个带有一些 eventid 的表中,以跟踪哪个事件与哪个操作相关。

您可以修改以下代码以满足您的需要。

DECLARE @starttime DATETIME = '2017-05-04 14:45:00'
DECLARE @endtime DATETIME= '2017-05-04 19:50:00'
DECLARE @starthour SMALLINT, @startminute SMALLINT, @endhour SMALLINT, @endminute SMALLINT

SELECT @starthour= DATEPART(HOUR, @starttime)
SELECT @endhour= DATEPART(HOUR, @endtime)
SELECT @startminute= 60-DATEPART(MINUTE, @starttime)
SELECT @endminute= DATEPART(MINUTE, @starttime)

IF (EXISTS (SELECT * 
                 FROM INFORMATION_SCHEMA.TABLES 
                 WHERE TABLE_SCHEMA = 'dbo' 
                 AND  TABLE_NAME = 'hourlyDuration'))
BEGIN
    DROP TABLE hourlyDuration
END
CREATE TABLE hourlyDuration
([hour] smallint,
[minute] smallint
)

--inserting first hour
INSERT INTO hourlyDuration 
([hour], [minute]) VALUES
(@starthour, @startminute)

--inserting between hours
WHILE (@endhour-@starthour)>1
BEGIN
  SET @starthour =@starthour+1
  INSERT INTO hourlyDuration ([hour], [minute]) VALUES
  (@starthour, 60)
END

--inserting last hour
IF @endhour<>@starthour
BEGIN
 INSERT INTO hourlyDuration 
 ([hour], [minute]) VALUES
 (@endhour, @endminute)
END

SELECT * FROM hourlyDuration
Run Code Online (Sandbox Code Playgroud)