Sql Сервер - Количество вхождений группы дата-время по заданному интервалу c - PullRequest
0 голосов
/ 11 марта 2020

У меня есть эта таблица с примерами данных:

MY_TABLE
------------------------------------------
ID    DateVal                other columns
------------------------------------------
1     2017-01-14 11:00:00    ...
2     2017-01-14 11:01:00    ...
3     2017-01-14 11:02:00    ...
4     2017-01-14 11:03:00    ...
5     2017-01-14 11:11:00    ... 
6     2017-01-14 11:11:30    ...
7     2017-01-14 11:15:00    ... 
8     2017-01-14 11:15:01    ...
9     2017-01-14 11:18:00    ...

Мне нужен такой результат:

start               end                 occurrences
-----------------------------------------------------------
2017-01-14 11:00    2017-01-14 11:05    4
2017-01-14 11:05    2017-01-14 11:10    0
2017-01-14 11:10    2017-01-14 11:15    3
2017-01-14 11:15    2017-01-14 11:20    2
...

В специфике c Мне нужен запрос, который извлекает все появления r aws в MY_TABLE в диапазоне 5 минут (значение диапазона является переменным).

Кто-то может мне помочь?

С уважением,

Ответы [ 3 ]

0 голосов
/ 11 марта 2020

Если вам не нужно, чтобы ваш начальный и конечный значения отражали точный диапазон: вы можете использовать что-то вроде DATEDIFF(minute, '2000-01-01', DateVal)/5 в качестве группировки, затем используйте MIN(DateVal) и MAX(DateVal) для своих start и end; но эти значения будут относиться к первой и последней транзакции в интервале, а не к границам интервала.

В качестве альтернативы, вы можете использовать рекурсивный CTE для генерации интервалов, а затем присоединить это к своим данным:

; WITH intervals AS (
   SELECT CAST('2017-11-01 00:00:00' AS DATETIME) AS `start`
       , CAST ('2017-11-01 00:05:00' AS DATETIME) AS `end`
   UNION ALL
   SELECT DATEADD(minute, 5, `start`) AS, DATEADD(minute, 5, `end`) AS end
   FROM intervals
   WHERE intervals.end < '2017-11-02 00:00:00'
)
SELECT i.`start`, i.`end`, COUNT(t.ID) AS occurrences
FROM intervals AS i
INNER JOIN MY_TABLE AS t ON t.DateVal >= i.`start` AND t.DateVal < i.End
GROUP BY i.`start`, i.`end`
ORDER BY i.`start`, i.`end`
;

Примечания:

  • буквенные значения даты могут быть скорректированы с учетом фактического диапазона, который вы хотите запросить
  • Если вы хотите, чтобы интервалы без активности были включены , ВНУТРЕННИЙ можно изменить на ЛЕВЫЙ
  • Поскольку ваш вопрос, как указано, имеет перекрывающиеся интервалы, я исходил из предположения, что DateVal на 5-минутной отметке принадлежит интервалу, который начинается с этого значения.
0 голосов
/ 11 марта 2020

Давайте возьмем генератор строк, который генерирует даты каждый диапазонSize от startDate:

DECLARE @rangeSize INT = 5;
DECLARE @startDate DATETIME = '2020-01-01 00:00';

WITH RG(D,D2) AS (
   SELECT @startDate AS D, DATEADD(MINUTE, @rangeSize, @startDate) AS D2
   UNION ALL
   SELECT DATEADD(MINUTE, @rangeSize, D), DATEADD(MINUTE, @rangeSize, D2)
   FROM   RG a
   WHERE  D < DATEADD(MINUTE, @rangeSize * 100, @startDate)
)

SELECT D,D2
FROM   RG
OPTION (MAXRECURSION 100);

Теперь давайте подключим его к вашим данным и посчитаем данные:

DECLARE @rangeSize INT = 5;
DECLARE @startDate DATETIME = '2020-01-01 00:00';

WITH RG(D,D2) AS (
   SELECT @startDate AS D, DATEADD(MINUTE, @rangeSize, @startDate) AS D2
   UNION ALL
   SELECT DATEADD(MINUTE, @rangeSize, D), DATEADD(MINUTE, @rangeSize, D2)
   FROM   RG a
   WHERE  D < DATEADD(MINUTE, @rangeSize * 100, @startDate)
)

SELECT r.D as StartDate, r.D2 as EndDate, COUNT(m.ID) as Count as EndDate
FROM   
  RG r
  LEFT JOIN
  my_table m ON m.dateval > r.D AND m.dateval <= r.D2
GROUP BY r.D, r.D2

OPTION (MAXRECURSION 100);

Примечание Я использовал > и <= для диапазона, потому что вы, кажется, классифицируете диапазон, например, с 15:01 до 20:00, тогда как для меня более естественно иметь 15:00 до 19:59 как "принадлежащий диапазон 15-20 "

0 голосов
/ 11 марта 2020

Вам нужно сгенерировать желаемые таймфреймы, а затем left join. Вот один из методов:

select v.dt, dateadd(minute, 5, v.dt) as end_dt, count(t.id)
from (values (convert(datetime, '2017-01-14 11:00')),
             (convert(datetime, '2017-01-14 11:05')),
             . . .
     ) v(dt) left join
     my_table t
     on t.dateval >= v.dt and
        t.dateval < dateadd(minute, 5, v.dt)
group by v.dt;

Примечание. Если вы хотите сделать это в течение более широкого диапазона времени, тогда удобно использовать таблицу подсчета или рекурсивный CTE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...