Подсчитайте количество интервалов менее 5 минут на группу - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть таблица, которая выглядит следующим образом:

Raw data

Мне нужно сгруппировать данные по Cat и Timestamp и дать счетчик для каждой группы.Группа определяется как динамическое 5-минутное временное окно, то есть оно может охватывать разные часы.

Результаты запроса должны давать следующее:

Results

Посмотрите на первые группы таблиц в желтом.Эти группы должны быть обнаружены и учитываться как одна, тогда как невыделенные группы также должны учитываться как одна

Теперь есть много решений, которые я прочитал в Stackoverflow, со следующими, которые я пробовалотносящиеся к делу:

  • Создать группы временных интервалов по 5 минут - это не работает, поскольку метки времени, охватывающие разные часы, не совпадают с одной и той же группой
  • Использовать ROWNUMBER () OVER(РАЗДЕЛЕНИЕ ПО категории, ПОРЯДОК ПО ВРЕМЕНИ) и присоединение к t1.Cat = t2.Cat и t1.rn + 1 = t2.rn.Фильтровать по DATEDIFF.Это не работает, так как могут быть обнаружены только пары из двух.Что если 5 временных меток последовательно находятся в течение 5 минут?

Я буду очень признателен за любую помощь с этим

См. Ниже для необработанных данных в таблице ascii

Необработанные данные

+---------------------+----------+
|      Timestamp      | Category |
+---------------------+----------+
| 2018-10-01 04:06:12 | Cat1     |
| 2018-10-01 05:07:18 | Cat1     |
| 2018-10-01 05:07:19 | Cat1     |
| 2018-10-01 05:07:20 | Cat1     |
| 2018-10-01 06:09:29 | Cat1     |
| 2018-10-01 07:24:12 | Cat2     |
| 2018-10-01 07:30:43 | Cat2     |
| 2018-10-01 07:59:13 | Cat2     |
| 2018-10-01 08:02:15 | Cat2     |
| 2018-10-01 10:09:25 | Cat2     |
| 2018-10-01 11:13:42 | Cat2     |
+---------------------+----------+

Ответы [ 3 ]

0 голосов
/ 30 ноября 2018

Вот один из способов сделать это

Первый шаг - классифицировать записи на основе того, находится ли предыдущая отметка времени в течение 5 минут.Если да, тогда присвойте ему row_number.

Для этого вам нужно получить следующие значения:

+---------------------+----------+-----------+
|     timestamp1      | category | grps_of_5 |
+---------------------+----------+-----------+
| 01/10/2018 05:06:12 | Cat1     |         1 |
| 01/10/2018 05:07:18 | Cat1     |           |
| 01/10/2018 05:07:19 | Cat1     |           |
| 01/10/2018 05:07:20 | Cat1     |           |
| 01/10/2018 06:09:29 | Cat1     |         5 |
| 01/10/2018 07:24:12 | Cat2     |         1 |
| 01/10/2018 07:30:43 | Cat2     |         2 |
| 01/10/2018 07:59:13 | Cat2     |         3 |
| 01/10/2018 08:02:15 | Cat2     |           |
| 01/10/2018 10:09:25 | Cat2     |         5 |
| 01/10/2018 11:13:42 | Cat2     |         6 |
+---------------------+----------+-----------+


After that i "copy" the values to fill up the nulls in groups using
max(grps_of_5) over(partition by category order by timestamp1)


This is done in the curated_data block and will look like this

+---------------------+----------+-----------+---------+
|     timestamp1      | category | grps_of_5 | max_val |
+---------------------+----------+-----------+---------+
| 01/10/2018 04:06:12 | Cat1     |         1 |       1 |
| 01/10/2018 05:07:18 | Cat1     |         2 |       2 |
| 01/10/2018 05:07:19 | Cat1     |           |       2 |
| 01/10/2018 05:07:20 | Cat1     |           |       2 |
| 01/10/2018 06:09:29 | Cat1     |         5 |       5 |
| 01/10/2018 07:24:12 | Cat2     |         1 |       1 |
| 01/10/2018 07:30:43 | Cat2     |         2 |       2 |
| 01/10/2018 07:59:13 | Cat2     |         3 |       3 |
| 01/10/2018 08:02:15 | Cat2     |           |       3 |
| 01/10/2018 10:09:25 | Cat2     |         5 |       5 |
| 01/10/2018 11:13:42 | Cat2     |         6 |       6 |
+---------------------+----------+-----------+---------+


After that i am counting the distinct max_val which will tell count all 5 minute intervals as a single group and others seperately.

with raw_data
  as(select timestamp1
            ,category
            ,case when datediff(mi,lag(timestamp1) over(partition by category order by timestamp1),timestamp1) >5 
                    or lag(timestamp1) over(partition by category order by timestamp1) is null
                  then row_number() over(partition by category order by timestamp1)                  
              end as grps_of_5
       from t  
     )
   ,curated_data
      as (select max(grps_of_5) over(partition by category order by timestamp1) as max_val
                 ,x.*
            from raw_data x
           )
 select category,count(distinct max_val) as cnt
   from curated_data
group by category            

+----------+------+
| category | cnt2 |
+----------+------+
| Cat1     |    3 |
| Cat2     |    5 |
+----------+------+

Отредактированная версия

Демонстрационная ссылка

https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=556e0ec16bb040b96b637e3da3e8178b

0 голосов
/ 30 ноября 2018

Это легко сделать с помощью LAG:

DECLARE @t TABLE (timestamp DATETIME, category VARCHAR(100));
INSERT INTO @t VALUES
('2018-10-01 04:06:12', 'CAT1'),
('2018-10-01 05:07:18', 'CAT1'),
('2018-10-01 05:07:19', 'CAT1'),
('2018-10-01 05:07:20', 'CAT1'),
('2018-10-01 06:09:29', 'CAT1'),
('2018-10-01 07:24:12', 'CAT2'),
('2018-10-01 07:30:43', 'CAT2'),
('2018-10-01 07:59:13', 'CAT2'),
('2018-10-01 08:02:15', 'CAT2'),
('2018-10-01 10:09:25', 'CAT2'),
('2018-10-01 11:13:42', 'CAT2');

WITH cte1 AS (
    SELECT timestamp, category, CASE WHEN LAG(timestamp) OVER (PARTITION BY category ORDER BY timestamp) > DATEADD(MINUTE, -5, timestamp) THEN 0 ELSE 1 END AS chg
    FROM @t
)
SELECT category, COUNT(CASE WHEN chg = 1 THEN 1 END)
FROM cte1
GROUP BY category

Чтобы понять, как это работает, сфокусируйтесь на том, как вычисляется столбец chg, и посмотрите на результаты cte:

timestamp                  category    chg
2018-10-01 04:06:12.000    CAT1        1
2018-10-01 05:07:18.000    CAT1        1
2018-10-01 05:07:19.000    CAT1        0
2018-10-01 05:07:20.000    CAT1        0
2018-10-01 06:09:29.000    CAT1        1
2018-10-01 07:24:12.000    CAT2        1
2018-10-01 07:30:43.000    CAT2        1
2018-10-01 07:59:13.000    CAT2        1
2018-10-01 08:02:15.000    CAT2        0
2018-10-01 10:09:25.000    CAT2        1
2018-10-01 11:13:42.000    CAT2        1
0 голосов
/ 30 ноября 2018

Пожалуйста, попробуйте ниже код:

SELECT * INTO #temp
FROM(
    SELECT '2018-10-01 05:06:12' AS Timestamp , 'Cat1' AS Category   
    UNION ALL
    SELECT '2018-10-01 05:07:18' AS Timestamp , 'Cat1' AS Category  
    UNION ALL
    SELECT '2018-10-01 05:07:19' AS Timestamp , 'Cat1' AS Category  
    UNION ALL
    SELECT '2018-10-01 05:07:20' AS Timestamp , 'Cat1' AS Category 
    UNION ALL
    SELECT '2018-10-01 06:09:29' AS Timestamp , 'Cat1' AS Category 
    UNION ALL
    SELECT '2018-10-01 07:24:12' AS Timestamp , 'Cat2' AS Category   
    UNION ALL
    SELECT '2018-10-01 07:30:43' AS Timestamp , 'Cat2' AS Category  
    UNION ALL
    SELECT '2018-10-01 07:59:13' AS Timestamp , 'Cat2' AS Category  
    UNION ALL
    SELECT '2018-10-01 08:02:15' AS Timestamp , 'Cat2' AS Category 
    UNION ALL
    SELECT '2018-10-01 10:09:25' AS Timestamp , 'Cat2' AS Category 
   UNION ALL
    SELECT '2018-10-01 11:13:42' AS Timestamp , 'Cat2' AS Category 
) AS T

SELECT  Category AS [Group], COUNT(CONVERT(DATE,Timestamp)) AS [Count]  FROM #temp GROUP By Category
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...