SQL查询包括没有计数的时间段

时间:2017-11-17 20:53:51

标签: sql sql-server tsql group-by

我在SQL Server 2014中工作。我有记录'计数'的表和计数的时间戳。计算期为两个小时,可以在任何一个小时开始。在下面的示例数据中,计数从16:00开始并经过18:00。计数区可以在01:30开始,并在03:30停止。

Timestamp   Count
16:00:31    1
16:00:42    1
16:16:04    1
16:16:06    1
16:45:10    1
16:45:31    1
16:45:32    1
17:16:45    1
17:16:52    1
17:16:53    1
17:33:19    1
17:34:01    1
17:45:03    1
17:46:08    1

我有一个查询,它在两小时的区间内总计15分钟的计数:

SELECT
    FORMAT(DATEPART(HOUR, [Timestamp]), '0#') + ':' + FORMAT(DATEPART(MINUTE, [TimeStamp]) / 15 * 15, '0#') AS QtrHrBeg
    , COUNT(*) AS CountTotal
FROM 
    [Sandbox].[trippetoe].[SURVEYCOUNTS]
GROUP BY 
    DATEPART(HOUR, [TIMESTAMP])
    , (DATEPART(MINUTE, [TIMESTAMP]) / 15 * 15)

结果如下:

QtrHrBeg    Count
16:00   2
16:15   2
16:45   3
17:15   3
17:30   2
17:45   2

我希望包括15分钟的间隔,其中没有计数 - 在本例中是从16:30和17:00开始的季度小时,如下所示:

QtrHrBeg    Count
16:00   2
16:15   2
16:30   0
16:45   3
17:00   0
17:15   3
17:30   2
17:45   2

我该怎么做?

2 个答案:

答案 0 :(得分:1)

见下文。

首先创建一个当天所有间隔的时间表,然后将其限制为所需的2小时窗口的间隔。

然后将其连接到数据表的总和,按0,其中连接返回null。

DECLARE @Data TABLE ([TimeStamp] TIME, [Count] INT)
INSERT INTO @Data ([TimeStamp],[Count])
VALUES ('16:00:31',1),
       ('16:00:42',1),
       ('16:16:04',1),
       ('16:16:06',1),
       ('16:45:10',1),
       ('16:45:31',1),
       ('16:45:32',1),
       ('17:16:45',1),
       ('17:16:52',1),
       ('17:16:53',1),
       ('17:33:19',1),
       ('17:34:01',1),
       ('17:45:03',1),
       ('17:46:08',1)

;with AllIntervals AS
(
    SELECT CONVERT(TIME,'00:00:00') AS Interval
    UNION ALL
    SELECT DATEADD(MINUTE,15,Interval)
    FROM AllIntervals
    WHERE Interval<'23:45:00'
), MyIntervals AS
    (
        SELECT CONVERT(VARCHAR(5),Interval,108) AS Interval
        FROM AllIntervals
        WHERE Interval >= (SELECT MIN(CONVERT(TIME,DATEADD(minute,(DATEDIFF(minute,0,[TimeStamp])/15)*15,0))) FROM @Data)
          AND Interval < DATEADD(HOUR,2,(SELECT MIN(CONVERT(TIME,DATEADD(minute,(DATEDIFF(minute,0,[TimeStamp])/15)*15,0))) FROM @Data))
    )

SELECT M.Interval, ISNULL(I.[Count],0)
FROM MyIntervals M
LEFT JOIN (SELECT CONVERT(TIME,DATEADD(minute,(DATEDIFF(minute,0,[TimeStamp])/15)*15,0)) AS Interval, SUM([Count]) AS Count
           FROM @Data
           GROUP BY CONVERT(TIME,DATEADD(minute,(DATEDIFF(minute,0,[TimeStamp])/15)*15,0))) I
   ON M.Interval=I.Interval

答案 1 :(得分:0)

您可以使用以下

  1. 在您要处理的数据中找到最短日期和最长日期,然后将这两个值舍入到最近的15
  2. 将段拆分为15分钟
  3. 左边加入您的数据,结果出来并按StartTime应用组,我使用的格式只显示时间格式
  4. 这种方法的好处是它可以在特定的时间间隔内工作,并且不会占用数据范围之外的任何时间间隔。

    with initial as(
      select dateadd(minute, datediff(minute,0,min([Time])) / 15 * 15, 0) as MinTime,
             dateadd(minute, datediff(minute,0,max([Time])) / 15 * 15, 0) as MaxTime
      from data
     ), times as(
       select StartTime = MinTime,
              EndTime =dateadd(millisecond,-1,dateadd(minute,15,MinTime)),
              MaxTime
       from initial
       union all
       select dateadd(millisecond,1,EndTime),
              dateadd(minute,15,EndTime),
              MaxTime
       from times
       where EndTime<MaxTime
     )
    
     select format(t.StartTime,'HH:mm') as [Time],isnull(sum(d.[Count]),0) as [Count]
     from times t
     left join data d on d.[Time] between t.StartTime and t.EndTime
     group by t.StartTime 
    

    这是输出

    Time    Count
    16:00   2
    16:15   2
    16:30   0
    16:45   3
    17:00   0
    17:15   3
    17:30   2
    17:45   2
    

    这是一个有效的demo

    希望这会对你有所帮助

    编辑

    我根据来自@HABO的评论将second的使用情况更改为millisecond,它将解决有时像16:59:59

    的情况