SQL Server 2014汇总事件持续时间(按半小时间隔)

时间:2018-07-13 16:37:01

标签: sql-server

我有一组数据,我需要根据这些数据将每个事件(以及resourceid或所有者)的多个不同事件持续时间分成一个或多个30分钟的时间间隔。持续时间可能跨越一个半小时以上的间隔,我需要该事件恰好在该间隔中花费的时间。那就是我遇到麻烦的地方,找不到任何其他问题解决方案似乎可以按照我的要求解决。

我确实知道如何按时间间隔进行计数,但是不知道如何以一种不愚蠢的方式处理时间间隔。我没有经验,将不胜感激,朝正确的方向努力,因为我一直在考虑这个问题,并且摆弄了两天,现在没有任何表现。我最坏的情况是逐行游标源数据,进行数学运算,然后将结果插入表中,但是我认为那完全是精妙的,所以甚至都没有尝试过。

哦,性能不是问题...数据量很低。使用SS 2014。

(而且,很抱歉,我不明白你们是如何嵌入代码片段的,所以对于任何假冒或其他愚蠢的行为,我都表示歉意。)

这是源数据的样子(我将在下面放置一个create table / insert,以获取一个所有者或resourceid的一整天的数据,以进行测试)

ResourceID  EventType   EventStartDateTime  EventEndDateTime        Duration  
16278       6       2018-07-11 10:53:58.163 2018-07-11 11:03:58.163 600  
16278       3       2018-07-11 11:03:58.163 2018-07-11 11:16:29.970 751  
16278       4       2018-07-11 11:16:29.970 2018-07-11 11:16:33.330 4  
16278       5       2018-07-11 11:16:33.330 2018-07-11 11:24:06.977 453  
16278       6       2018-07-11 11:24:06.977 2018-07-11 11:31:31.633 445  
16278       7       2018-07-11 11:31:31.633 2018-07-11 11:31:31.633 0  
16278       1       2018-07-11 12:30:44.020 2018-07-11 17:15:55.173 17111  
16278       2       2018-07-11 12:30:44.023 2018-07-11 12:33:23.437 159  
16278       3       2018-07-11 12:33:23.437 2018-07-11 12:38:55.467 332  
etc.

这是我想要的结果,除了空白处填充:

declare @FirstDay smalldatetime = '20180711', 
        @LastDay  smalldatetime = '20180711';

select top (24*2*datediff(day, @FirstDay, dateadd(day,1,@LastDay)))
  dateadd(minute, 30*(row_number() over (order by (select NULL))-1), 
@FirstDay) as IntervalStartTime
  , 0 as resourceid, '' as eventtype, 0 as SecWithinInterval
into ##Interval
from master.dbo.spt_values;

这是创建表/插入:

create table source_data (resourceid int, eventtype int, eventstartdatetime 
datetime
    , eventenddatetime datetime, duration int)

insert into source_data values
(16278,6,2018-07-11 10:53:58.163,2018-07-11 11:03:58.163,600),  
(16278,3,2018-07-11 11:03:58.163,2018-07-11 11:16:29.970,751),  
(16278,4,2018-07-11 11:16:29.970,2018-07-11 11:16:33.330,4),  
(16278,5,2018-07-11 11:16:33.330,2018-07-11 11:24:06.977,453),  
(16278,6,2018-07-11 11:24:06.977,2018-07-11 11:31:31.633,445),  
(16278,7,2018-07-11 11:31:31.633,2018-07-11 11:31:31.633,0),  
(16278,1,2018-07-11 12:30:44.020,2018-07-11 17:15:55.173,17111),  
(16278,2,2018-07-11 12:30:44.023,2018-07-11 12:33:23.437,159),  
(16278,3,2018-07-11 12:33:23.437,2018-07-11 12:38:55.467,332),  
(16278,4,2018-07-11 12:38:55.467,2018-07-11 12:38:58.677,3),  
(16278,5,2018-07-11 12:38:58.677,2018-07-11 12:45:09.793,371),  
(16278,6,2018-07-11 12:45:09.793,2018-07-11 12:47:20.173,131),  
(16278,3,2018-07-11 12:47:20.173,2018-07-11 12:54:51.057,451), 
(16278,4,2018-07-11 12:54:51.057,2018-07-11 12:54:53.383,2),  
(16278,5,2018-07-11 12:54:53.383,2018-07-11 12:59:27.373,274),  
(16278,6,2018-07-11 12:59:27.373,2018-07-11 13:02:25.813,178),  
(16278,3,2018-07-11 13:02:25.813,2018-07-11 13:02:49.173,24),  
(16278,4,2018-07-11 13:02:49.173,2018-07-11 13:02:51.490,2),  
(16278,5,2018-07-11 13:02:51.490,2018-07-11 13:05:30.453,159),  
(16278,3,2018-07-11 13:05:30.453,2018-07-11 13:05:30.453,0),  
(16278,4,2018-07-11 13:05:30.453,2018-07-11 13:05:33.183,3),  
(16278,5,2018-07-11 13:05:33.183,2018-07-11 13:15:55.777,622),  
(16278,6,2018-07-11 13:15:55.777,2018-07-11 13:16:18.970,23),  
(16278,2,2018-07-11 13:16:18.970,2018-07-11 13:23:32.787,434),  
(16278,3,2018-07-11 13:23:32.787,2018-07-11 13:28:12.907,280),  
(16278,4,2018-07-11 13:28:12.907,2018-07-11 13:28:16.073,4),  
(16278,5,2018-07-11 13:28:16.073,2018-07-11 13:32:47.177,271),  
(16278,6,2018-07-11 13:32:47.177,2018-07-11 13:37:45.500,298),  
(16278,3,2018-07-11 13:37:45.500,2018-07-11 13:43:59.183,374),  
(16278,4,2018-07-11 13:43:59.183,2018-07-11 13:44:01.507,2),  
(16278,5,2018-07-11 13:44:01.507,2018-07-11 13:50:04.983,363),  
(16278,6,2018-07-11 13:50:04.983,2018-07-11 13:50:43.860,39),  
(16278,3,2018-07-11 13:50:43.860,2018-07-11 13:57:21.817,398),  
(16278,4,2018-07-11 13:57:21.817,2018-07-11 13:57:24.177,3),  
(16278,5,2018-07-11 13:57:24.177,2018-07-11 14:07:57.677,633),  
(16278,6,2018-07-11 14:07:57.677,2018-07-11 14:14:08.553,371),  
(16278,3,2018-07-11 14:14:08.553,2018-07-11 14:28:57.117,889),  
(16278,4,2018-07-11 14:28:57.117,2018-07-11 14:28:59.440,2),  
(16278,5,2018-07-11 14:28:59.440,2018-07-11 14:31:50.793,171),  
(16278,6,2018-07-11 14:31:50.793,2018-07-11 14:33:08.727,78),  
(16278,3,2018-07-11 14:33:08.727,2018-07-11 14:38:30.820,322),  
(16278,2,2018-07-11 14:38:30.820,2018-07-11 14:44:22.197,352),  
(16278,2,2018-07-11 14:44:22.197,2018-07-11 15:01:45.453,1043),  
(16278,3,2018-07-11 15:01:45.453,2018-07-11 15:13:38.823,713),  
(16278,4,2018-07-11 15:13:38.823,2018-07-11 15:13:42.247,4),  
(16278,5,2018-07-11 15:13:42.247,2018-07-11 15:18:57.147,315),  
(16278,6,2018-07-11 15:18:57.147,2018-07-11 15:19:12.297,15),  
(16278,3,2018-07-11 15:19:12.297,2018-07-11 15:29:43.060,631),  
(16278,4,2018-07-11 15:29:43.060,2018-07-11 15:29:46.160,3),  
(16278,5,2018-07-11 15:29:46.160,2018-07-11 15:30:37.130,51),  
(16278,6,2018-07-11 15:30:37.130,2018-07-11 15:30:44.783,7),  
(16278,3,2018-07-11 15:30:44.783,2018-07-11 15:37:46.373,422),  
(16278,4,2018-07-11 15:37:46.373,2018-07-11 15:37:49.080,3),  
(16278,5,2018-07-11 15:37:49.080,2018-07-11 15:43:52.273,363),  
(16278,6,2018-07-11 15:43:52.273,2018-07-11 15:48:54.730,302),  
(16278,3,2018-07-11 15:48:54.730,2018-07-11 15:56:47.407,473),  
(16278,4,2018-07-11 15:56:47.407,2018-07-11 15:56:49.820,2),  
(16278,5,2018-07-11 15:56:49.820,2018-07-11 16:01:40.780,291),  
(16278,6,2018-07-11 16:01:40.780,2018-07-11 16:04:02.403,142),  
(16278,3,2018-07-11 16:04:02.403,2018-07-11 16:20:53.963,1011),  
(16278,4,2018-07-11 16:20:53.963,2018-07-11 16:21:00.817,7),  
(16278,3,2018-07-11 16:21:00.817,2018-07-11 16:35:54.190,894),  
(16278,4,2018-07-11 16:35:54.190,2018-07-11 16:35:56.473,2),  
(16278,5,2018-07-11 16:35:56.473,2018-07-11 16:38:37.587,161),  
(16278,6,2018-07-11 16:38:37.587,2018-07-11 16:45:29.563,412),  
(16278,3,2018-07-11 16:45:29.563,2018-07-11 16:57:20.893,711),  
(16278,4,2018-07-11 16:57:20.893,2018-07-11 16:57:24.000,4),  
(16278,5,2018-07-11 16:57:24.000,2018-07-11 17:10:22.210,778),  
(16278,6,2018-07-11 17:10:22.210,2018-07-11 17:15:55.173,333),  
(16278,7,2018-07-11 17:15:55.173,2018-07-11 17:15:55.173,0)  

非常感谢大家,为您提供的任何帮助!

2 个答案:

答案 0 :(得分:0)

此示例使用数字表来得出时间间隔。这是一段快速而又肮脏的代码,并且不假定您已有数字表。出于本示例的目的,示例数据已加载到名为## source_data的全局临时表中。

SET NOCOUNT ON
-- Create a temporary numbers table to demonstrate its use. 
-- We only need numbers up to 47, but will be creating numbers up to 336 to cover
-- periods of up to a week. This table will also include zero.

Declare @DailyIntervals int = 48,
    @maxDays int = 7

-- This calculates the number of recursive inserts needed to reach your maximum value
-- NOTE: This is based off of manually inserting your first four values into the table first!

DECLARE @loop int
SET @loop = CEILING(LOG(@DailyIntervals * @maxDays, 2))-2
--SELECT @loop

Declare @m int
CREATE TABLE ##Nums (i int primary key clustered);

INSERT INTO ##Nums VALUES (1), (2), (3), (4);   -- Seed the table

SET @m = 4

WHILE @loop > 0
BEGIN
    INSERT INTO ##nums SELECT I + @m FROM ##Nums
    SET @m = @@ROWCOUNT * 2 -- max value in table now
    SET @loop = @loop - 1
END

INSERT INTO ##nums Values (0)   -- add the zero value

--SELECT MAX(I) FROM ##Nums

-- Look at July 11th only for now.
DECLARE @BeginDt datetime = '2018-07-11',
    @EndDt datetime = '2018-07-11';

-- Build a working table of half hour intervals
WITH hhrs as (
    SELECT Dateadd(MINUTE, 30 * i, @BeginDt) as StartTm,
        Dateadd(MINUTE, 30 * (i+1), @BeginDt) as EndTm
    FROM ##Nums
    WHERE i BETWEEN 0 and (DateDiff(Day, @BeginDt, @EndDt) * 48 + 47)
    ),
-- Get all of the data except duration
Src as (
    SELECT 
        sd.resourceid,
        sd.eventtype,
        CASE
            WHEN sd.eventstartdatetime <= StartTm
                THEN StartTm
            Else sd.eventstartdatetime
        End as EventStart,
        CASE
            WHEN sd.eventEnddatetime > EndTm
                THEN EndTm
            Else sd.eventenddatetime
        End as EventEnd
    FROM hhrs h
    INNER JOIN ##source_data sd
        ON sd.eventstartdatetime < EndTm
        AND sd.eventenddatetime >= StartTm
    )
-- Final output including duration
SELECT 
    ResourceID,
    EventType,
    EventStart,
    EventEnd,
    DateDiff(SECOND, EventStart, EventEnd) as Duration
FROM Src
ORDER BY EventStart, EventEnd
DROP TABLE ##Nums

这是我从样本数据中收到的输出:

ResourceID EventType  EventStart                 EventEnd                   Duration
16278        6        2018-07-11 10:53:58.163    2018-07-11 11:00:00.000    362
16278        6        2018-07-11 11:00:00.000    2018-07-11 11:03:58.163    238
16278        3        2018-07-11 11:03:58.163    2018-07-11 11:16:29.970    751
16278        4        2018-07-11 11:16:29.970    2018-07-11 11:16:33.330    4
16278        5        2018-07-11 11:16:33.330    2018-07-11 11:24:06.977    453
16278        6        2018-07-11 11:24:06.977    2018-07-11 11:30:00.000    354
16278        6        2018-07-11 11:30:00.000    2018-07-11 11:31:31.633    91
16278        7        2018-07-11 11:31:31.633    2018-07-11 11:31:31.633    0
16278        1        2018-07-11 12:30:44.020    2018-07-11 13:00:00.000    1756
16278        2        2018-07-11 12:30:44.023    2018-07-11 12:33:23.437    159
16278        3        2018-07-11 12:33:23.437    2018-07-11 12:38:55.467    332
16278        4        2018-07-11 12:38:55.467    2018-07-11 12:38:58.677    3
16278        5        2018-07-11 12:38:58.677    2018-07-11 12:45:09.793    371
16278        6        2018-07-11 12:45:09.793    2018-07-11 12:47:20.173    131
16278        3        2018-07-11 12:47:20.173    2018-07-11 12:54:51.057    451
16278        4        2018-07-11 12:54:51.057    2018-07-11 12:54:53.383    2
16278        5        2018-07-11 12:54:53.383    2018-07-11 12:59:27.373    274
16278        6        2018-07-11 12:59:27.373    2018-07-11 13:00:00.000    33
16278        6        2018-07-11 13:00:00.000    2018-07-11 13:02:25.813    145
16278        1        2018-07-11 13:00:00.000    2018-07-11 13:30:00.000    1800
16278        3        2018-07-11 13:02:25.813    2018-07-11 13:02:49.173    24
16278        4        2018-07-11 13:02:49.173    2018-07-11 13:02:51.490    2
16278        5        2018-07-11 13:02:51.490    2018-07-11 13:05:30.453    159
16278        3        2018-07-11 13:05:30.453    2018-07-11 13:05:30.453    0
16278        4        2018-07-11 13:05:30.453    2018-07-11 13:05:33.183    3
16278        5        2018-07-11 13:05:33.183    2018-07-11 13:15:55.777    622
16278        6        2018-07-11 13:15:55.777    2018-07-11 13:16:18.970    23
16278        2        2018-07-11 13:16:18.970    2018-07-11 13:23:32.787    434
16278        3        2018-07-11 13:23:32.787    2018-07-11 13:28:12.907    280
16278        4        2018-07-11 13:28:12.907    2018-07-11 13:28:16.073    4
16278        5        2018-07-11 13:28:16.073    2018-07-11 13:30:00.000    104
16278        5        2018-07-11 13:30:00.000    2018-07-11 13:32:47.177    167
16278        1        2018-07-11 13:30:00.000    2018-07-11 14:00:00.000    1800
16278        6        2018-07-11 13:32:47.177    2018-07-11 13:37:45.500    298
16278        3        2018-07-11 13:37:45.500    2018-07-11 13:43:59.183    374
16278        4        2018-07-11 13:43:59.183    2018-07-11 13:44:01.507    2
16278        5        2018-07-11 13:44:01.507    2018-07-11 13:50:04.983    363
16278        6        2018-07-11 13:50:04.983    2018-07-11 13:50:43.860    39
16278        3        2018-07-11 13:50:43.860    2018-07-11 13:57:21.817    398
16278        4        2018-07-11 13:57:21.817    2018-07-11 13:57:24.177    3
16278        5        2018-07-11 13:57:24.177    2018-07-11 14:00:00.000    156
16278        5        2018-07-11 14:00:00.000    2018-07-11 14:07:57.677    477
16278        1        2018-07-11 14:00:00.000    2018-07-11 14:30:00.000    1800
16278        6        2018-07-11 14:07:57.677    2018-07-11 14:14:08.553    371
16278        3        2018-07-11 14:14:08.553    2018-07-11 14:28:57.117    889
16278        4        2018-07-11 14:28:57.117    2018-07-11 14:28:59.440    2
16278        5        2018-07-11 14:28:59.440    2018-07-11 14:30:00.000    61
16278        5        2018-07-11 14:30:00.000    2018-07-11 14:31:50.793    110
16278        1        2018-07-11 14:30:00.000    2018-07-11 15:00:00.000    1800
16278        6        2018-07-11 14:31:50.793    2018-07-11 14:33:08.727    78
16278        3        2018-07-11 14:33:08.727    2018-07-11 14:38:30.820    322
16278        2        2018-07-11 14:38:30.820    2018-07-11 14:44:22.197    352
16278        2        2018-07-11 14:44:22.197    2018-07-11 15:00:00.000    938
16278        2        2018-07-11 15:00:00.000    2018-07-11 15:01:45.453    105
16278        1        2018-07-11 15:00:00.000    2018-07-11 15:30:00.000    1800
16278        3        2018-07-11 15:01:45.453    2018-07-11 15:13:38.823    713
16278        4        2018-07-11 15:13:38.823    2018-07-11 15:13:42.247    4
16278        5        2018-07-11 15:13:42.247    2018-07-11 15:18:57.147    315
16278        6        2018-07-11 15:18:57.147    2018-07-11 15:19:12.297    15
16278        3        2018-07-11 15:19:12.297    2018-07-11 15:29:43.060    631
16278        4        2018-07-11 15:29:43.060    2018-07-11 15:29:46.160    3
16278        5        2018-07-11 15:29:46.160    2018-07-11 15:30:00.000    14
16278        5        2018-07-11 15:30:00.000    2018-07-11 15:30:37.130    37
16278        1        2018-07-11 15:30:00.000    2018-07-11 16:00:00.000    1800
16278        6        2018-07-11 15:30:37.130    2018-07-11 15:30:44.783    7
16278        3        2018-07-11 15:30:44.783    2018-07-11 15:37:46.373    422
16278        4        2018-07-11 15:37:46.373    2018-07-11 15:37:49.080    3
16278        5        2018-07-11 15:37:49.080    2018-07-11 15:43:52.273    363
16278        6        2018-07-11 15:43:52.273    2018-07-11 15:48:54.730    302
16278        3        2018-07-11 15:48:54.730    2018-07-11 15:56:47.407    473
16278        4        2018-07-11 15:56:47.407    2018-07-11 15:56:49.820    2
16278        5        2018-07-11 15:56:49.820    2018-07-11 16:00:00.000    191
16278        5        2018-07-11 16:00:00.000    2018-07-11 16:01:40.780    100
16278        1        2018-07-11 16:00:00.000    2018-07-11 16:30:00.000    1800
16278        6        2018-07-11 16:01:40.780    2018-07-11 16:04:02.403    142
16278        3        2018-07-11 16:04:02.403    2018-07-11 16:20:53.963    1011
16278        4        2018-07-11 16:20:53.963    2018-07-11 16:21:00.817    7
16278        3        2018-07-11 16:21:00.817    2018-07-11 16:30:00.000    540
16278        3        2018-07-11 16:30:00.000    2018-07-11 16:35:54.190    354
16278        1        2018-07-11 16:30:00.000    2018-07-11 17:00:00.000    1800
16278        4        2018-07-11 16:35:54.190    2018-07-11 16:35:56.473    2
16278        5        2018-07-11 16:35:56.473    2018-07-11 16:38:37.587    161
16278        6        2018-07-11 16:38:37.587    2018-07-11 16:45:29.563    412
16278        3        2018-07-11 16:45:29.563    2018-07-11 16:57:20.893    711
16278        4        2018-07-11 16:57:20.893    2018-07-11 16:57:24.000    4
16278        5        2018-07-11 16:57:24.000    2018-07-11 17:00:00.000    156
16278        5        2018-07-11 17:00:00.000    2018-07-11 17:10:22.210    622
16278        1        2018-07-11 17:00:00.000    2018-07-11 17:15:55.173    955
16278        6        2018-07-11 17:10:22.210    2018-07-11 17:15:55.173    333
16278        7        2018-07-11 17:15:55.173    2018-07-11 17:15:55.173    0

答案 1 :(得分:0)

您可以使用一点“递归”(与CTE一起)来建立时间表,并将其与source_data结合起来以找到所有区间的交集。 在我的解决方案中,我没有使用您的“持续时间”字段,因为无论如何我必须计算间隔的长度(以秒为单位)。 CTE EventDays全天“创建”(如果查询超过100天,则必须更改MAXRECURSION选项或以较大的间隔(例如,甚至几个月或几年)以CTE开始),而CTE HalfHours会创建所有haf-hour-建立时间表的每一天的时间间隔:

DECLARE @FirstDay smalldatetime = '20180711', 
        @LastDay  smalldatetime = '20180711';

WITH 
  EventDays (EventDay, NextDay, MaxDay) AS (
    SELECT @FirstDay, DATEADD(day, 1, @FirstDay), @LastDay
    UNION ALL
    SELECT NextDay, DATEADD(day, 1, NextDay), MaxDay
    FROM EventDays WHERE NextDay <= MaxDay
  ),
  HalfHours (StartTime, EndTime, MaxTime) AS (
    SELECT EventDay, DATEADD(minute, 30, EventDay), NextDay
    FROM EventDays
    UNION ALL
    SELECT EndTime, DATEADD(minute, 30, EndTime), MaxTime
    FROM HalfHours WHERE EndTime < MaxTime
  )
SELECT ResourceID, EventType, isec.StartTime, isec.EndTime,
  DATEDIFF(second, isec.StartTime, isec.EndTime) AS Duration
FROM source_data sd
  INNER JOIN HalfHours hh 
    ON sd.EventEndDatetime > hh.StartTime AND sd.EventStartDatetime < hh.EndTime
  CROSS APPLY (VALUES ( -- intersection StartTime and EndTime
    CASE
      WHEN sd.EventStartDatetime > hh.StartTime THEN sd.EventStartDatetime 
      ELSE hh.StartTime
    END,
    CASE
      WHEN sd.EventEndDatetime < hh.EndTime THEN sd.EventEndDatetime 
      ELSE hh.EndTime
    END)
  ) isec (StartTime, EndTime)
ORDER BY isec.StartTime;