Вы можете использовать оконные функции для пошагового построения ответа.
Шаг 1 - Упорядочить строки по отметке времени и использовать LEAD
, чтобы выяснить, когда заканчивается каждая «группа».То есть, когда значение id
изменяется в следующей строке.Пометьте любую строку как «Y», если это правда.
Шаг 2 - Посчитайте отмеченные значения «Y» до текущей строки.Этот счет будет «номером группы».Это дает каждой последовательной группе с одинаковым идентификатором один и тот же «номер группы».
Шаг 3 - Теперь возьмите отметку времени min
и max
в каждой «группе» как время начала и окончанияэто событие.
Возможно, оно не так компактно и круто, как другие возможные решения, но у меня гораздо больше шансов вспомнить, как оно работало, когда я вернусь к нему через 6 месяцев.Это всего лишь я.
Здесь все вместе.
WITH input (id, ts) AS (
SELECT 1, TO_DATE( '01.01.2018 13:30','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1, TO_DATE( '01.01.2018 13:31','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 2, TO_DATE( '01.01.2018 13:32','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 2, TO_DATE( '01.01.2018 13:33','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1, TO_DATE( '01.01.2018 13:34','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 3, TO_DATE( '01.01.2018 13:35','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 3, TO_DATE( '01.01.2018 13:35','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 3, TO_DATE( '01.01.2018 13:35','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 3, TO_DATE( '01.01.2018 13:36','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1, TO_DATE( '01.01.2018 13:37','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 3, TO_DATE( '01.01.2018 13:38','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 4, TO_DATE( '01.01.2018 13:39','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 4, TO_DATE( '01.01.2018 13:40','DD.MM.YYYY HH24:MI') FROM DUAL UNION ALL
SELECT 1, TO_DATE( '01.01.2018 13:40','DD.MM.YYYY HH24:MI') FROM DUAL ),
-- Solution starts here
input_with_group_markers as (
SELECT id, ts,
case when lead(id,1) over ( order by ts ) != id THEN 'Y' ELSE NULL END last_row_in_group
FROM input
),
grouped_input as (
SELECT igwm.*, count(last_row_in_group) OVER ( order by ts rows between unbounded preceding and 1 preceding ) group_number
FROM input_with_group_markers igwm )
SELECT min(id) id,
to_char(min(ts),'DD.MM.YYYY HH24:MI') event_start,
to_char(max(ts),'DD.MM.YYYY HH24:MI') event_end
FROM grouped_input
group by group_number
order by group_number;