Распределение данных между значениями NULL и не NULL - PullRequest
0 голосов
/ 13 декабря 2018

Я опрашиваю ресурс на предмет его текущего состояния и записываю эту информацию в таблицу.Иногда ресурс недоступен, поэтому состояние будет NULL.

Я пытаюсь разбить данные на последовательные блоки строк, где состояние NOT NULL, а затем блок строк, где status равен NULL.Из этих разделов я хотел бы получить дополнительную информацию, такую ​​как самые ранние и последние метки времени этих блоков, количество строк этого блока и некоторые другие.

Пример данных может выглядеть следующим образом

DECLARE @data TABLE
(
 ID INT IDENTITY,
 STATE NVARCHAR(10) NULL,
 TS DATETIME2(0) NOT NULL
);

INSERT INTO @data
(
 STATE,
 TS
)
VALUES
(N'A', DATEADD(SECOND, 0, GETDATE())),
(N'B', DATEADD(SECOND, 1, GETDATE())),
(NULL, DATEADD(SECOND, 2, GETDATE())),
(NULL, DATEADD(SECOND, 3, GETDATE())),
(NULL, DATEADD(SECOND, 4, GETDATE())),
(N'A', DATEADD(SECOND, 5, GETDATE())),
(N'C', DATEADD(SECOND, 6, GETDATE())),
(N'D', DATEADD(SECOND, 7, GETDATE())),
(N'B', DATEADD(SECOND, 8, GETDATE())),
(NULL, DATEADD(SECOND, 9, GETDATE())),
(NULL, DATEADD(SECOND, 10, GETDATE()))

ID  STATE   TS
1   A       2018-12-13 17:01:38
2   B       2018-12-13 17:01:39
3   NULL    2018-12-13 17:01:40
4   NULL    2018-12-13 17:01:41
5   NULL    2018-12-13 17:01:42
6   A       2018-12-13 17:01:43
7   C       2018-12-13 17:01:44
8   D       2018-12-13 17:01:45
9   B       2018-12-13 17:01:46
10  NULL    2018-12-13 17:01:47
11  NULL    2018-12-13 17:01:48

Обратите внимание, что это упрощено, поскольку временные метки могут быть нерегулярными (не всегда с разницей в 1 секунду) и что это сокращено до одного ресурса, его имя опущено (в реальных данных есть некоторые ресурсы со столбцом имени)

Для того, что я пытаюсь получить, эти данные представляют собой четыре раздела, состоящие из ID (1, 2) [блок ненулевых значений], затем (2,4,5) [NULL values], затем (6, 7,8, 9) [снова ненулевое значение] и, наконец, (10, 11)

Минимальные значения TS и количество для этих разделов должны быть

17:01:38    2    non-NULL
17:01:40    3    NULL
17:01:43    4    non-NULL
17:01:47    2    NULL

Я пробовал группировать и управлять окнами,но оба обрабатывают все различные значения одинаково.У кого-нибудь есть решение для этого?

SQL-SERVER 2014

1 Ответ

0 голосов
/ 13 декабря 2018

Это проблема пробелов и островков

Вы можете попробовать использовать оконную функцию ROW_NUMBER для получения номера разрыва и группировки по нему.

SELECT min(TS) ts,count(*) cnt,val
FROM (
SELECT *,
 ROW_NUMBER() OVER(ORDER BY ID) - 
 ROW_NUMBER() OVER(PARTITION BY (CASE WHEN STATE IS NOT NULL THEN 1 ELSE 0 END) ORDER BY ID) grp,
 (CASE WHEN STATE IS NOT NULL THEN 'non-NULL' END) val
FROM @data
) t1
GROUP BY grp,val
ORDER BY min(TS)

sqlfiddle

...