У меня есть упрощенная таблица в ClickHouse, в которой хранятся события изменения статуса триггера
CREATE TABLE trigger_events_test (
`CreatedAt` DateTime,
`Id` UUID,
`TriggerId` Int,
`Status` Enum8('Ok' = 1,
'Problem1' = 2,
'Problem2' = 3,
'Problem3' = 4,
'Problem4' = 5,
'Disabled' = 6)
) ENGINE = MergeTree() PARTITION BY (toYYYYMM(CreatedAt)) ORDER BY (CreatedAt, TriggerId) SETTINGS index_granularity = 8192;
Допустим, таблица содержит 5 записей:
INSERT into trigger_events_test(CreatedAt, Id, TriggerId, Status)
values
('2020-02-14 10:16:00', '9be6f472-aa15-418f-ac6d-e8ceb8dc462e', 1, 'Problem1'),
('2020-02-14 10:17:00', '260bbf0c-fbbc-44b4-835f-dfb3cdad11f1', 1, 'Ok'),
('2020-02-14 10:18:00', 'cb35f07e-a539-4932-8f26-d95df8de6686', 1, 'Problem2'),
('2020-02-14 10:19:00', '7c5a78d7-8b41-4353-89c2-232edcbb2457', 1, 'Problem3'),
('2020-02-14 10:20:00', '260bbf0c-fbbc-44b4-835f-dfb3cdad11f1', 1, 'Ok'),
Я хочу выбрать историю изменения статуса триггера (id = 1) с продолжительностью статуса на основе предыдущего статуса. Поэтому я могу сделать запрос
SELECT
Id,
TriggerId,
Status,
CreatedAt,
if(neighbor(TriggerId,1) = TriggerId, neighbor(CreatedAt,1,now()), now()) AS DateEnd,
ABS(CreatedAt - DateEnd) AS Duration
FROM trigger_events_test
ORDER BY TriggerId ASC, CreatedAt ASC
, который дает правильный ответ
Id |TriggerId|Status |CreatedAt |DateEnd |Duration|
------------------------------------|---------|--------|-------------------|-------------------|--------|
9be6f472-aa15-418f-ac6d-e8ceb8dc462e| 1|Problem1|2020-02-14 10:16:00|2020-02-14 10:17:00| 60|
260bbf0c-fbbc-44b4-835f-dfb3cdad11f1| 1|Ok |2020-02-14 10:17:00|2020-02-14 10:18:00| 60|
cb35f07e-a539-4932-8f26-d95df8de6686| 1|Problem2|2020-02-14 10:18:00|2020-02-14 10:19:00| 60|
7c5a78d7-8b41-4353-89c2-232edcbb2457| 1|Problem3|2020-02-14 10:19:00|2020-02-14 10:20:00| 60|
260bbf0c-fbbc-44b4-835f-dfb3cdad11f1| 1|Ok |2020-02-14 10:20:00|2020-02-14 10:54:15| 2055|
Но на самом деле я хочу фильтровать записи по дате с обоих концов и по статусам. Я сделал подзапрос, который возвращает не то, что я ожидал.
SELECT *
FROM (SELECT
Id,
TriggerId,
Status,
CreatedAt,
if(neighbor(TriggerId,1) = TriggerId, neighbor(CreatedAt,1,now()), now()) AS DateEnd,
ABS(CreatedAt - DateEnd) AS Duration
FROM trigger_events_test
ORDER BY TriggerId ASC, CreatedAt ASC)
WHERE Status IN ('Problem1', 'Problem2', 'Problem3', 'Problem4') AND (DateEnd >= '2020-02-14 10:17:00' AND CreatedAt <= now())
Результат:
Id |TriggerId|Status |CreatedAt |DateEnd |Duration|
------------------------------------|---------|--------|-------------------|-------------------|--------|
9be6f472-aa15-418f-ac6d-e8ceb8dc462e| 1|Problem1|2020-02-14 10:16:00|2020-02-14 10:18:00| 120|
cb35f07e-a539-4932-8f26-d95df8de6686| 1|Problem2|2020-02-14 10:18:00|2020-02-14 10:19:00| 60|
7c5a78d7-8b41-4353-89c2-232edcbb2457| 1|Problem3|2020-02-14 10:19:00|2020-02-14 10:58:03| 2343|
Как вы можете видеть, "Проблема 1" теперь возвращает 120 сек c длительности, и Проблема 3 думает, что имеет еще не закончено. Я полагаю, что ClickHouse оптимизирует запрос и выполняет условие условия в подзапросе.
Может кто-нибудь помочь мне выяснить, как сделать правильный запрос?