How count of numbers id for a period of time

Viewed 74

I am looking for a way to count the number of id in a period of time every 30 minutes.

I wrote a SQL query, but the result is incorrect

CREATE TABLE [dbo].[#tabl]
(
    [Id] [varchar](100) NULL,
    [TIMEStart] [datetime] NULL,
    [TIMEEnd] [datetime] NULL
) ON [PRIMARY]


INSERT INTO [dbo].[#tabl] VALUES ('1', '2020-04-01 00:05:00.000', '2020-04-01 00:10:00.000')
INSERT INTO [dbo].[#tabl] VALUES ('2', '2020-04-01 00:11:00.000', '2020-04-01 00:29:00.000')
INSERT INTO [dbo].[#tabl] VALUES ('3', '2020-04-01 00:12:00.000', '2020-04-01 00:55:00.000')

WITH CTE AS 
(
    SELECT
        [Id], 
        DATEADD(MINUTE, (DATEDIFF(MINUTE, [TIMEStart], [TIMEEnd]) / 30) * 30, 0) AS RangeTime
    FROM
        [dbo].[#tabl]
    GROUP BY
        [Id], DATEADD(MINUTE, (DATEDIFF(MINUTE, [TIMEStart],[TIMEEnd]) / 30) * 30, 0)
)
SELECT numreq, RangeTime
FROM 
    (SELECT COUNT(DISTINCT id) AS numreq, RangeTime
     FROM CTE
     GROUP BY RangeTime) temp

Correct result - table:

numreq       RangeTime
-------------------------------------
3            1900-01-01 00:00:00.000 
1            1900-01-01 00:30:00.000 

Period of time:

1900-01-01 00:00:00.000 - includes 3 id:1, 2, 3
1900-01-01 00:30:00.000 - includes 1 id:1
1 Answers

I think what you need is to create a list of RangeTime values that lie within the range of the TIMEStart and TIMEEnd values in tabl (which you can do with a recursive CTE), then you can JOIN that list back to tabl on an overlapping time range and count the number of rows that overlap each RangeTime:

WITH CTE AS (
  SELECT DATEADD(MINUTE,(DATEDIFF(MINUTE, 0, MIN([TIMEStart]))/30)*30,0) as RangeTime, 
         MAX([TIMEEnd]) AS MaxTime
  FROM [dbo].[tabl]
  UNION ALL
  SELECT DATEADD(MINUTE, 30, RangeTime), MaxTime
  FROM CTE
  WHERE DATEADD(MINUTE, 30, RangeTime) < MaxTime
)
SELECT RangeTime, COUNT(tabl.Id) AS numreq 
FROM CTE
LEFT JOIN tabl ON tabl.TIMEStart < DATEADD(MINUTE, 30, RangeTime)
              AND RangeTime <= tabl.TIMEEnd
GROUP BY RangeTime

Output:

RangeTime               numreq
2020-04-01T00:00:00Z    3
2020-04-01T00:30:00Z    1

Demo on SQLFiddle

Note: I've presumed you want the actual time for the range, not times starting at the beginning of 1900...

Related